1396: 识别子串

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 381  Solved: 243
[Submit][Status][Discuss]

Description

Input

一行,一个由小写字母组成的字符串S,长度不超过10^5

Output

L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长.

Sample Input

agoodcookcooksgoodfood

Sample Output

1
2
3
3
2
2
3
3
2
2
3
3
2
1
2
3
3
2
1
2
3
4
 
 
想法:
如果s[i..j]为识别串,s[i-y..j+x]同样也是识别串,可以通过枚举一个端点来得到最短识别串。
设wi=max{lcp(i,j)}+1=max{height[rank[i]],height[rank[i+1]]}+1
s[i..j]为识别子串<==>j-i+1>=wi。
即j>=i+max{height[rank[i]],height[rank[i+1]]},令hi=i+max{height[rank[i]],height[rank[i+1]]}
得到ansi=min{max(j-i+1,hi-i+1)}i<=j,分开求:
①ansj=min(j-i+1)hi<=j;树状数组维护
②ansj=min(hi-i+1)i<=j,hi>=j;线段树维护[i,hi]的区间最值。
显然h(i)>h(i-1),当 hx-x<hy-y&&x>y,y就无用了,于是使用单调队列。
O(nlogn)
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
const int len(100000),limt(255);
int str[len+10],sfa[len+10],rank[len+10],height[len+10];
int tmp[len+10],p[len+10],cnt[len+10];
int n,c[len+10],ans[len+10],q[len+10],li,hi;char ch[len+10];
struct data{int x,y;}h[len+10];
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
bool com(int x,int y,int l){return (rank[x]==rank[y])&&(rank[x+l]==rank[y+l]);}
void doubling()
{
for(int i=1;i<=n;i++){rank[i]=str[i];sfa[i]=i;}
for(int pos=0,l=0,sigma=limt;pos<n;sigma=pos)
{
pos=0;
for(int i=n-l+1;i<=n;i++)p[++pos]=i;
for(int i=1;i<=n;i++)if(sfa[i]>l)p[++pos]=sfa[i]-l;
memset(cnt,0,sizeof(int)*(sigma+1));pos=0;
for(int i=1;i<=n;i++)cnt[rank[i]]++;
for(int i=1;i<=sigma;i++)cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--)sfa[cnt[rank[p[i]]]--]=p[i];
for(int i=1;i<=n;i++)tmp[sfa[i]]=com(sfa[i],sfa[i-1],l)?pos:++pos;
for(int i=1;i<=n;i++)rank[i]=tmp[i];
l=!l?1:l<<1;
}
for(int i=1;i<=n;i++)rank[sfa[i]]=i;
for(int i=1,k,j;i<=n;i++)
{
k=sfa[rank[i]-1];
if(!k)continue;
j=height[rank[i-1]];
if(j)j--;
while(str[i+j]==str[k+j])j++;
height[rank[i]]=j;
}
}
int query(int x){int sum=0;for(;x;x-=x&(-x))sum=max(sum,c[x]);return sum;}
void put(int x,int y){for(;x<=n;x+=x&(-x))c[x]=max(c[x],y);}
int main()
{
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
scanf("%s",ch);n=strlen(ch);
for(int i=1;i<=n;i++)str[i]=ch[i-1]-'a'+1;
doubling();
for(int i=1;i<=n;i++)
{
h[i].x=i+max(height[rank[i]],height[rank[i]+1]);
h[i].y=i;
if(h[i].x>n+1)printf("NO");
}
for(int i=1,t;i<=n;i++)
{
if(h[i].x!=n+1)ans[h[i].y]=h[i].x-h[i].y+1;
else ans[h[i].y]=n;
t=query(h[i].y);
if(t)ans[h[i].y]=min(h[i].y-t+1,ans[h[i].y]);
if(h[i].x!=n+1)put(h[i].x,h[i].y);
}
q[li=1]=1;hi=1;
for(int i=2;i<=n;i++)
{
while(h[q[hi]].x<i&&hi<=li)hi++;
if(hi<=li&&h[q[hi]].x>=i&&h[q[hi]].x!=n+1)ans[h[i].y]=min(ans[h[i].y],h[q[hi]].x-h[q[hi]].y+1);
if(h[i].x!=n+1)
{
while(h[q[li]].x-h[q[li]].y>h[i].x-h[i].y&&li>=hi)li--;
q[++li]=i;
}
}
for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
return 0;
}

  

BZOJ 1396:识别子串 SA+树状数组+单调队列的更多相关文章

  1. 大视野 1012: [JSOI2008]最大数maxnumber(线段树/ 树状数组/ 单调队列/ 单调栈/ rmq)

    1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 9851  Solved: 4318[Submi ...

  2. BZOJ.1396.识别子串(后缀自动机/后缀数组 线段树)

    题目链接 SAM:能成为识别子串的只有那些|right|=1的节点代表的串. 设这个节点对应原串的右端点为r[i],则如果|right[i]|=1,即\(s[\ [r_i-len_i+1,r_i-le ...

  3. bzoj 1396 识别子串 后缀树+线段树

    题目大意 给定一个长度\(\le100000\)的字符串 求每一个位置的最短识别子串 对于位置\(x\),能识别子串\(s[i...j]\)的条件是 1.\(i\le x \le j\) 2.\(s[ ...

  4. BZOJ 1396: 识别子串( 后缀数组 + 线段树 )

    这道题各位大神好像都是用后缀自动机做的?.....蒟蒻就秀秀智商写一写后缀数组解法..... 求出Height数组后, 我们枚举每一位当做子串的开头. 如上图(x, y是height值), Heigh ...

  5. bzoj 3262 陌上花开 - CDQ分治 - 树状数组

    Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当 ...

  6. BZOJ 1901 Zju2112 Dynamic Rankings ——树状数组套主席树

    [题目分析] BZOJ这个题目抄的挺霸气. 主席树是第一时间想到的,但是修改又很麻烦. 看了别人的题解,原来还是可以用均摊的思想,用树状数组套主席树. 学到了新的姿势,2333o(* ̄▽ ̄*)ブ [代 ...

  7. [BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

    题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...

  8. BZOJ 2743: [HEOI2012]采花 [树状数组 | 主席树]

    题意: 查询区间中出现次数$>2$的颜色个数 一眼主席树,区间中$l \le last[i] \le r$的个数减去$l \le last[last[i]] \le r$的个数,搞两颗主席树来做 ...

  9. BZOJ.4826.[AHOI/HNOI2017]影魔(树状数组/莫队 单调栈)

    BZOJ LOJ 洛谷 之前看\(mjt\)用莫队写了,以为是一种正解,码了3h结果在LOJ T了没A= = 心态爆炸(upd:发现是用C++11(NOI)交的,用C++11交就快一倍了...) 深刻 ...

随机推荐

  1. Apache2.2安装图解

    Apache2.2安装图解 2010-12-14 15:32:44|  分类: 不学无术之杂 |  标签:安装  端口  httpd  apache2.2  服务器   |字号 订阅 Apache音译 ...

  2. 【转】eclipse修改workspace

    [转]eclipse修改workspace 以下方法选其中一种 1.进入 Window > Preferences > General > Startup and Shutdown ...

  3. adt eclipse 配置问题 error:could not open ...jvm.cfg

    在安装adt eclipse后,打开eclipse提示error:could not open eclipse\jre\lib\amd64\jvm.cfg 据网上显示原因应该是以前安装过java,然后 ...

  4. freemaker宏的用法

    freemaker宏 定义:定义一个标签,标签体中可以包含参数,开始标签和结束标签可以包含内容,内容中可以通过${}方式引用标签体中定义的参数 用法:页面引入标签,通过标签可以直接输出标签的内容 He ...

  5. Coreseek 安装问题

    Ubuntu下安装coreseek mmseg出现了cannot find input file: src/Makefile.in 解决方法如下 >autoheader >automake ...

  6. Fenwick Tree / Binary Indexed Tree

    Motivation: Given a 1D array of n elements. [2, 5, -1, 3, 6] range sum query: what's the sum from 2n ...

  7. Mac 下sublime的插件

    最近更换了本本,入了港行的Mac pro,来替代原来的Thinkpad,在windows上工作做完之后,搭建了一下开发环境,eclipse是必须的,但是luna没有html editor,然后就在 e ...

  8. 13.Python略有小成(装饰器,递归函数)

    Python(装饰器,递归函数) 一.开放封闭原则 ​ 软件面世时,不可能把所有的功能都设计好,再未来的一两年功能会陆续上线,定期更新迭代,软件之前所用的源代码,函数里面的代码以及函数的调用方式一般不 ...

  9. python接口自动化(三十九)- logger 日志 - 上(超详解)

    简介 Python的logging模块提供了通用的日志系统,可以方便第三方模块或者是应用使用.这个模块提供不同的日志级别,并可以采用不同的方式记录日志,比如文件,HTTP GET/POST,SMTP, ...

  10. JMeter(6) jenkins测试报告及邮件优化

    jenkins邮件 使用jenkins执行完任务自动将测试结果发送到邮箱,效果如下:     生成html报告 build文件设置     jenkins设置 SummaryReport写入邮件正文 ...