题目链接:hdu 4436 str2int
题意:
给你n个字符串,每个字符串都是由数字构成,现在让你将这n个字符串所有的不重复子串构成的十进制数字加起来mod2012.
题解:
似乎这种不重复的子串问题,用后缀自动机都比较无脑搞。
首先将所有的串连起来,中间插个特殊字符,然后建立后缀自动机。
然后拓扑排序,从跟开始往下dp。
sum[v]=Σ(sum[x]*10+cnt[x]*j),其中cnt[x]表示有多少条路径能到x这个节点,转移为cnt[v]=Σcnt[x] (x能转移到v),j为这个节点代表的数字。
1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=(a);i<=(b);++i) 4 using namespace std; 5 6 const int N=2e5+7,tyn=11,M=N*2,P=2012; 7 struct SAM{ 8 int tr[M][tyn],f[M],ml[M],ed,last,p,x,r,q; 9 int b[M],d[M],cnt[M],sum[M]; 10 inline int gid(char x){return x-'0';} 11 inline void nc(int s,int &p){ 12 ml[p=++ed]=s,f[ed]=cnt[ed]=sum[ed]=0,mst(tr[ed],0); 13 } 14 void clear(){ed=0,nc(0,last);} 15 void add(int w){ 16 nc(ml[x=last]+1,p),last=p; 17 while(x&&!tr[x][w])tr[x][w]=p,x=f[x]; 18 if(!x)f[p]=1; 19 else if(ml[x]+1==ml[q=tr[x][w]])f[p]=q; 20 else{ 21 nc(ml[x]+1,r),f[r]=f[q],f[p]=f[q]=r; 22 memcpy(tr[r],tr[q],sizeof(tr[r])); 23 while(x&&tr[x][w]==q)tr[x][w]=r,x=f[x]; 24 } 25 } 26 void upright(int mx=0){ 27 F(i,0,ed)d[i]=0; 28 F(i,1,ed)d[mx<ml[i]?mx=ml[i]:ml[i]]++; 29 F(i,1,mx)d[i]+=d[i-1]; 30 F(i,1,ed)b[d[ml[i]]--]=i; 31 } 32 void build(char *s){for(int i=1;s[i];i++)add(gid(s[i]));} 33 34 void solve() 35 { 36 int ans=0; 37 cnt[1]=1; 38 F(i,1,ed) 39 { 40 int x=b[i],v; 41 F(j,0,9) 42 { 43 v=tr[x][j]; 44 if((i==1&&j==0)||!v)continue; 45 cnt[v]=(cnt[v]+cnt[x])%P; 46 sum[v]=(sum[v]+sum[x]*10+cnt[x]*j)%P; 47 } 48 ans=(ans+sum[x])%P; 49 } 50 printf("%d\n",ans); 51 } 52 }sam; 53 54 char s[N]; 55 int n; 56 57 int main(){ 58 while(~scanf("%d",&n)) 59 { 60 sam.clear(); 61 F(i,1,n)scanf("%s",s+1),sam.build(s),sam.add(10); 62 sam.upright(),sam.solve(); 63 } 64 return 0; 65 }