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. 提取html里面url()导入的图片正则表达式

    之前写过一次,后来无意发现还是有问题,比如 <a onclick="openZoosUrl('chatwin','param'); 这个click事件函数里面就有url()部分,造成了 ...

  2. JAVA正则表达式之 Pattern介绍

    1.简介: java.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包. 它包括两个类:Pattern和Matcher. Pattern 一个Pattern是一个正则表 ...

  3. VMWare安装Ubuntu 16.04

    1.Ubuntu安装文件下载 到Ubuntu官网下载安装包,有Bit Torrent.Network installer多种方式下载. 推荐使用中国地区的镜像下载,我是用华科的校园网下载速度是非常感人 ...

  4. 小程序与Spring项目数据交互

    上一篇博客刚说了利用Postman来测试Spring Boot项目,测试通过后就可以和小程序进行交互了. 首先要在微信开发者工具里面,点击"详情",勾选上"不校验合法域名 ...

  5. HDU - 6025 Coprime Sequence(gcd+前缀后缀)

    Do you know what is called ``Coprime Sequence''? That is a sequence consists of nnpositive integers, ...

  6. js call apply bind

    call.apply.bindcat.call(dog, a, b) == cat.apply(dog, [a, b]) == (cat.bind(dog, a, b))() 1.作用 改变函数内的t ...

  7. js 实现发布订阅模式

    /* Pubsub */ function Pubsub(){ //存放事件和对应的处理方法 this.handles = {}; } Pubsub.prototype = { //传入事件类型typ ...

  8. python的编码问题整理

    一.编码和解码 1.编码(encode):将人类可以识别的语言(英文.中文等)转化成机器语言(01串)的过程,用于存储. 2.解码(decode):将机器语言转化成人类可识别的语言的过程,用于显示. ...

  9. 消息中间件之ActiveMQ(非原创)

    文章大纲 一.消息中间件基础知识二.ActiveMQ介绍三.ActiveMQ下载安装(Windows版本)四.Java操作ActiveMQ代码实战五.Spring整合ActiveMQ代码实战六.项目源 ...

  10. PostgreSQL - invalid input syntax for type timestamp with time zone

    问题 在执行以下sql时报错: select COALESCE(null,null,now(),''); 报错如下: SQL Error [22007]: ERROR: invalid input s ...