「NOI2016」优秀的拆分

这不是个SAM题,只是个LCP题目

95分的Hash很简单,枚举每个点为开头和末尾的AA串个数,然后乘一下之类的。

考虑怎么快速求“每个点为开头和末尾的AA串个数”

考虑枚举A的长度,然后在序列中每|A|个位置放一个关键点,这样每个AA至少都经过了一个关键点。

然后求相邻两个关键点的lcs,lcp,画画图匹配一下,可以把区间内的都求出来了。

可以Hash二分或者sa或者sam


Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using std::min;
const int N=120010;
struct SAM
{
int head[N],to[N],Next[N],cnt;
void add(int u,int v){to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;}
int dfn[N],st[18][N],Log[N],dep[N],pos[N],clock;
void dfs(int now)
{
st[0][dfn[now]=++clock]=now;
for(int i=head[now];i;i=Next[i])
dep[to[i]]=dep[now]+1,dfs(to[i]),st[0][++clock]=now;
}
int LCA(int x,int y)
{
x=dfn[x],y=dfn[y];
if(x>y) std::swap(x,y);
int d=Log[y+1-x];
x=st[d][x],y=st[d][y-(1<<d)+1];
return dep[x]<dep[y]?x:y;
}
int len[N],par[N],ch[N][26],las=1,tot=1;
void extend(int c)
{
int now=++tot,p=las;
len[now]=len[p]+1;
while(p&&!ch[p][c]) ch[p][c]=now,p=par[p];
if(!p) par[now]=1;
else
{
int x=ch[p][c];
if(len[x]==len[p]+1) par[now]=x;
else
{
int y=++tot;
len[y]=len[p]+1;
par[y]=par[x];
memcpy(ch[y],ch[x],sizeof ch[y]);
while(p&&ch[p][c]==x) ch[p][c]=y,p=par[p];
par[x]=par[now]=y;
}
}
las=now;
}
void init(char *s,int typ)
{
int n=strlen(s+1);
for(int i=1;i<=n;i++) extend(s[i]-'a'),pos[typ?n+1-i:i]=las;
for(int i=1;i<=tot;i++) add(par[i],i);
clock=0,dep[1]=1,dfs(1);
Log[0]=-1;for(int i=1;i<=clock;i++) Log[i]=Log[i>>1]+1;
for(int j=1;j<=17;j++)
for(int i=1;i<=clock-(1<<j)+1;i++)
{
int x=st[j-1][i],y=st[j-1][i+(1<<j-1)];
st[j][i]=dep[x]<dep[y]?x:y;
}
}
void clear()
{
memset(ch,0,sizeof ch);
memset(par,0,sizeof par);
memset(len,0,sizeof len);
memset(head,0,sizeof head);
cnt=0,las=tot=1;
}
int query(int x,int y)
{
return len[LCA(pos[x],pos[y])];
}
}LCS,LCP;
int d[N],f[N],g[N];
void work(char *s,int *f)
{
int n=strlen(s+1);
LCS.init(s,0);
std::reverse(s+1,s+n+1);
LCP.init(s,1);
for(int l=1;l<=n;l++)
{
for(int i=1;i+l<=n;i+=l)
{
int a=min(LCS.query(i,i+l),l),b=min(LCP.query(i,i+l),l);
if(a+b-1<l) continue;
int ss=i-a+1,tt=ss+a+b-l-1;
++d[ss+l*2-1],--d[tt+l*2];
}
}
for(int i=1;i<=n;i++) f[i]=f[i-1]+d[i];
memset(d,0,sizeof d);
LCP.clear(),LCS.clear();
}
char s[N];
int main()
{
int T;scanf("%d",&T);
while(T--)
{
memset(f,0,sizeof f);
memset(g,0,sizeof g);
scanf("%s",s+1);
int n=strlen(s+1);
work(s,f);
work(s,g);
std::reverse(g+1,g+1+n);
ll ans=0;
for(int i=1;i<=n;i++) ans=ans+f[i-1]*g[i];
printf("%lld\n",ans);
}
return 0;
}

2019.3.15

「NOI2016」优秀的拆分 解题报告的更多相关文章

  1. 「NOI2016」循环之美 解题报告

    「NOI2016」循环之美 对于小数\(\frac{a}{b}\),如果它在\(k\)进制下被统计,需要满足要求并且不重复. 不重复我们确保这个分数是最简分数即\((a,b)=1\) 满足要求需要满足 ...

  2. LOJ#2083. 「NOI2016」优秀的拆分

    $n \leq 30000$的字符串,问其所有子串的所有AABB形式的拆分有多少种.$t \leq 10$组询问. $n^3$过80,$n^2$过95,鬼去写正解.. $n^2$:先枚举一次算每个位置 ...

  3. 洛谷 P4714 「数学」约数个数和 解题报告

    P4714 「数学」约数个数和 题意(假):每个数向自己的约数连边,给出\(n,k(\le 10^{18})\),询问\(n\)的约数形成的图中以\(n\)为起点长为\(k\)的链有多少条(注意每个点 ...

  4. 「NOI2013」树的计数 解题报告

    「NOI2013」树的计数 这什么神题 考虑对bfs重新编号为1,2,3...n,然后重新搞一下dfs序 设dfs序为\(dfn_i\),dfs序第\(i\)位对应的节点为\(pos_i\) 一个暴力 ...

  5. 「FJOI2018」领导集团问题 解题报告

    「FJOI2018」领导集团问题 题意:给你一颗\(n\)个点的带点权有根树,选择一个点集\(S\),使得点集中所有祖先的点权$\le \(子孙的点权,最大化\)|S|$(出题人语死早...) 一个显 ...

  6. 「SP25784」BUBBLESORT - Bubble Sort 解题报告

    SP25784 BUBBLESORT - Bubble Sort 题目描述 One of the simplest sorting algorithms, the Bubble Sort, can b ...

  7. 「SP122」STEVE - Voracious Steve 解题报告

    SP122 STEVE - Voracious Steve 题意翻译 Problem Steve和他的一个朋友在玩游戏,游戏开始前,盒子里有 n个甜甜圈,两个人轮流从盒子里抓甜甜圈,每次至少抓 1个, ...

  8. 「Luogu」[JSOI2007]字符加密 解题报告

    题面 思路: 作为一个后缀数组的初学者,当然首先想到的是后缀数组 把\(s\)这个串首尾相接,扩展为原来的两倍,就能按后缀数组的方法处理 证明: 神仙一眼就看出这是后缀的裸题,我这个蒟蒻想了半天想不出 ...

  9. 「P5004」专心OI - 跳房子 解题报告

    题面 把\(N\)个无色格子排成一行,选若干个格子染成黑色,要求每个黑色格子之间至少间隔\(M\)个格子,求方案数 思路: 矩阵加速 根据题面,这一题似乎可以用递推 设第\(i\)个格子的编号为\(i ...

随机推荐

  1. 第五章 动态SQL 批量操作

    用于实现动态SQL的元素主要有 if trim where set choose(when.otherwise) foreach MyBatis  缓存 一级缓存 在test类中 调用相同的方法 第二 ...

  2. bridge br0 docker 网络问题 Docker Container与Docker Host

    Docker学习笔记:Docker 网络配置 - docker ppt - docker中文社区http://www.docker.org.cn/dockerppt/111.html Bridge t ...

  3. fiddler查看IP地址和请求响应时间

    (一)fiddler查看IP地址 1.点击菜单栏rules——customize rules… 2.ctrl+f搜索“static function main” 3.在main函数里加入下面一行代码, ...

  4. 关于百度地图API和jqGrid踩到的坑

    1.百度地图重新标记问题 var map = new BMap.Map("map"); ...... var marker = new BMap.Marker(point); // ...

  5. React Native之本地文件系统访问组件react-native-fs的介绍与使用

    React Native之本地文件系统访问组件react-native-fs的介绍与使用 一,需求分析 1,需要将图片保存到本地相册: 2,需要创建文件,并对其进行读写 删除操作. 二,简单介绍 re ...

  6. [官网]Red Hat Enterprise Linux Release Dates

    Red Hat Enterprise Linux Release Dates https://access.redhat.com/articles/3078 The tables below list ...

  7. Java案例-用户注册邮箱绑定激活功能实现

    <–start–> 需求描述:当客户打开收到邮箱激活码的邮件,点击激活链接,正确填写激活码后就会完成邮箱激活的步骤. 在后台编程代码编写中,有以下几个要点: ① 接收客户的手机号码和邮箱激 ...

  8. jQuery ajax解析xml文件demo

    解析xml文件,然后将城市列表还原到下拉列表框中:当选择下拉列表框时,在对应的文本框中显示该城市信息. 前端代码: <!doctype html> <html> <hea ...

  9. vue前端框架面试问题汇总

    1.active-class是哪个组件的属性?嵌套路由怎么定义?答:vue-router模块的router-link组件. 2.怎么定义vue-router的动态路由?怎么获取传过来的动态参数? 答: ...

  10. AspectJ用注解替换xml配置

    AspectJ基于注解的使用 AspectJ简介 AspectJ是一个基于Java语言的AOP框架,一般 其主要用途:自定义开发 一般情况下spring自动生成代理,要配置aop, 首先确定目标类,a ...