题目描述
(其实两道题就是数据范围不一样)
Description
XX 在进行字符串研究的时候,遇到了一个十分棘手的问题。在这个问题中,给定一个字符串 S,与一个整数 K,定义 S 的子串 T=S(i, j)是关于第 K 位的识别子串,满足以下两个条件:
1、i≤K≤j。
2、子串 T 只在 S 中出现过一次。
例如,S=”banana”,K=5,则关于第 K 位的识别子串有”nana”,”anan”,”anana”,”nan”,”banan”和”banana”。
现在,给定 S,XX 希望知道对于 S 的每一位,最短的识别子串长度是多少,请你来帮助他。
Input
仅一行,输入长度为 N 的字符串 S。
Output
输出 N 行,每行一个整数,第 i 行的整数表示对于第 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
Data Constraint
Hint
N<=500000
Description
现在同学们把大多数作业都做完了,但是却被最后一个题给难住了。
一般地,对于一个字符串S,和S中第k个字符,定义子串T=S(i..j)为一个关于k的识别子串,当且仅当
1、i<=k<=j。
2、T在S中只出现一次。
比如,对于banana的第5个字符,“nana”,“anan”,“anana”,“nan”,“banan”和“banana”都是关于它的识别子串。
自然,识别子串越短越好(太长了也就失去意义了),现在请你计算出对于一个字符串S,关于S的每一位的最短识别子串分别有多长。
Input
一行,一个长度为L的字符串S,S只包含小写字母。
Output
L行,每行1个整数,第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
Data Constraint
第一个点 L=100
第二个点 L=1000
第三个点 L=5000
第四个点到第十个点 L=100000
100%
直接SAM建图,然后处理出每个位置至少向左扩展多少位才能使其唯一
之后线段树乱搞
一个优化:
往fail链跳时,如果对应的next不是当前所指就退
因为如果一个点的next不同,fail链上的肯定不同
code
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define Maxlen 1000010
using namespace std;
int next[Maxlen][26];
int c[Maxlen];
int d[Maxlen];
int T[Maxlen];
int sum[Maxlen];
int fail[Maxlen];
int tr[20000000][2];
int mx[Maxlen];
char s[Maxlen];
int f[Maxlen];
int ans[Maxlen];
int C[26];
bool bz[26];
int i,j,k,l,Len,len,last,I,J,K,L,S,S2,ch,h,t,N;
struct B{
int x,y;
} b[Maxlen];
__attribute__((optimize("-O2")))
bool cmp(B a,B b)
{
return a.x<b.x;
}
__attribute__((optimize("-O2")))
void down(int t)
{
if (tr[t][1])
{
tr[t][0]=min(tr[t][0],tr[t][1]);
tr[t*2][1]=min(tr[t*2][1],tr[t][1]);
tr[t*2+1][1]=min(tr[t*2+1][1],tr[t][1]);
tr[t][1]=233333333;
}
}
__attribute__((optimize("-O2")))
void change(register int t,int l,int r,int x,int y,int s)
{
register int mid=(l+r)/2;
down(t);
if (x<=l && r<=y)
{
tr[t][1]=s;
down(t);
return;
}
if (x<=mid)
change(t*2,l,mid,x,y,s);
if (mid<y)
change(t*2+1,mid+1,r,x,y,s);
tr[t][0]=min(min(tr[t*2][0],tr[t*2][1]),min(tr[t*2+1][0],tr[t*2+1][1]));
}
__attribute__((optimize("-O2")))
void New(int x)
{
len++;
T[len]=i+1;
mx[len]=mx[x]+1;
}
__attribute__((optimize("-O2")))
void bfs()
{
h=0;
t=1;
d[1]=1;
while (h<t)
{
h++;
fo(i,0,25)
if (next[d[h]][i])
{
if (!f[next[d[h]][i]])
f[next[d[h]][i]]=f[d[h]]+1;
c[next[d[h]][i]]--;
if (!c[next[d[h]][i]])
d[++t]=next[d[h]][i];
}
}
}
__attribute__((optimize("-O2")))
void getans(register int t,int l,int r)
{
register int mid=(l+r)/2;
if (l==r)
{
tr[t][0]=min(tr[t][0],tr[t][1]);
tr[t][1]=0;
printf("%d\n",min(tr[t][0],ans[l]-l+1));
return;
}
else
down(t);
getans(t*2,l,mid);
getans(t*2+1,mid+1,r);
}
__attribute__((optimize("-O2")))
int main()
{
memset(tr,127,sizeof(tr));
len=1,last=1;
mx[1]=0;
sum[1]=1;
fail[1]=0;
i=0;
s[0]=getchar();
while (s[i]>='a')
s[++i]=getchar();
Len=i-1;
fo(i,0,Len) bz[s[i]-'a']=1;
N=-1;
fo(i,0,25)
if (bz[i])
C[i]=++N;
fo(i,0,Len)
{
ch=C[s[i]-'a'];
New(last);
next[last][ch]=len;
K=last;
last=next[last][ch];
for (j=fail[K]; j; j=fail[j])
if (!next[j][ch])
next[j][ch]=last;
else
{
if ((mx[j]+1)!=mx[next[j][ch]])
{
k=next[j][ch];
New(j);
fo(l,0,N)
next[len][l]=next[k][l];
fail[len]=fail[k];
fail[last]=len,fail[k]=len;
for (l=j; next[l][ch]==k; l=fail[l]) //优化
next[l][ch]=len;
}
else
fail[last]=next[j][ch];
break;
}
if (!j)
fail[last]=1;
sum[last]++;
}
fo(i,1,len)
b[i].x=mx[i],b[i].y=i;
stable_sort(b+1,b+len+1,cmp);
fd(i,len,1)
sum[fail[b[i].y]]+=sum[b[i].y];
fo(i,1,len)
{
fo(j,0,N)
c[next[i][j]]++;
}
bfs();
j=0;
fo(i,2,len)
if (sum[i]==1)
{
change(1,1,Len+1,T[i]-f[i]+1,T[i],f[i]);
if (T[i]>f[i])
{
j++;
b[j].x=T[i]-f[i];
b[j].y=T[i];
}
}
stable_sort(b+1,b+j+1,cmp);
k=233333333;
fd(i,Len+1,1)
{
while (j && i<=b[j].x)
{
k=min(k,b[j].y);
j--;
}
ans[i]=k;
}
getans(1,1,Len+1);
}