【BZOJ 3238】 3238: [Ahoi2013]差异(SAM)
3238: [Ahoi2013]差异
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 3047 Solved: 1375Description
Input
一行,一个字符串S
Output
一行,一个整数,表示所求值
Sample Input
cacaoSample Output
54
HINT
2<=N<=500000,S由小写英文字母组成
Source
【分析】
这题先把sigma len 加上。
然后考虑一下减掉的是什么。
对于每个子串,假设出现次数是x,那么对答案的贡献就是x*(x-1)/2*2即ans-=x*(x-1)。
这个用SAM对每个点的right进行计算即可。
当然也可以用后缀数组。【后缀数组要用单调栈吧?套路啊。。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 500010 8 #define LL long long 9 10 struct node 11 { 12 int son[30],pre,step,rt; 13 // node() {rt=0;} 14 }t[Maxn*2]; 15 int v[Maxn*2],q[Maxn*2]; 16 17 struct sam 18 { 19 int last,tot; 20 void extend(int k) 21 { 22 int np=++tot,p=last; 23 t[np].step=t[p].step+1; 24 t[np].rt=1; 25 while(p&&!t[p].son[k]) 26 { 27 t[p].son[k]=np; 28 p=t[p].pre; 29 } 30 if(!p) t[np].pre=1; 31 else 32 { 33 int q=t[p].son[k]; 34 if(t[q].step==t[p].step+1) t[np].pre=q; 35 else 36 { 37 int nq=++tot; 38 memcpy(t[nq].son,t[q].son,sizeof(t[nq].son)); 39 t[nq].step=t[p].step+1; 40 t[nq].pre=t[q].pre; 41 t[q].pre=t[np].pre=nq; 42 while(p&&t[p].son[k]==q) 43 { 44 t[p].son[k]=nq; 45 p=t[p].pre; 46 } 47 } 48 } 49 last=np; 50 } 51 void init() 52 { 53 memset(v,0,sizeof(v)); 54 for(int i=1;i<=tot;i++) v[t[i].step]++; 55 for(int i=1;i<=tot;i++) v[i]+=v[i-1]; 56 for(int i=tot;i>=1;i--) q[v[t[i].step]--]=i; 57 58 for(int i=tot;i>=1;i--) 59 { 60 int nw=q[i]; 61 t[t[nw].pre].rt+=t[nw].rt; 62 } 63 } 64 }sam; 65 66 char s[Maxn]; 67 68 int main() 69 { 70 LL ans=0; 71 scanf("%s",s); 72 int l=strlen(s); 73 sam.last=sam.tot=1; 74 for(int i=0;i<l;i++) sam.extend(s[i]-'a'+1); 75 ans=1LL*l*(l+1)*(l-1)/2; 76 sam.init();t[1].step=0; 77 for(int i=2;i<=sam.tot;i++) 78 { 79 ans-=1LL*(t[i].step-t[t[i].pre].step)*t[i].rt*(t[i].rt-1); 80 } 81 printf("%lld\n",ans); 82 return 0; 83 }
2017-04-17 21:06:17