【题目链接】
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=51267
【题意】
给定n个字符串,计算所有忽略前导0的子串形成的不重整数之和。
【思路】
既然是处理子串问题,我们可以合并串之后构造一个SAM。
SAM的性质:结点u代表的字符串集是从根到u路径上的所有结点代表的字符串集之并,结点u所代表的字符串集为最长串的所有子串。
记cnt[u]为状态u代表的字符串个数,sum[u]代表状态u代表的字符串对应的数之和。
拓扑排序后,设p为当前结点,trans(p,j)为np,则有:
cnt[np]+=cnt[p]
sum[np]+=sum[p]*10+cnt[p]*j
不走$边,第一次不走0边。
【代码】
1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 11 using namespace std; 12 13 typedef long long ll; 14 const int N = 2e5+10; 15 const int MOD = 2012; 16 17 int n,len; 18 char s[N]; 19 int sum[N],cnt[N]; 20 int sz,last,fa[N],ch[N][11],l[N],c[N],b[N]; 21 22 void add(int c) 23 { 24 int p=last,np=++sz; last=np; 25 l[np]=l[p]+1; 26 for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np; 27 if(!p) fa[np]=1; 28 else { 29 int q=ch[p][c]; 30 if(l[q]==l[p]+1) fa[np]=q; 31 else { 32 int nq=++sz; l[nq]=l[p]+1; 33 memcpy(ch[nq],ch[q],sizeof(ch[q])); 34 fa[nq]=fa[q]; 35 fa[q]=fa[np]=nq; 36 for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; 37 } 38 } 39 } 40 void init() 41 { 42 sz=last=1; 43 len=0; 44 memset(sum,0,sizeof(sum)); 45 memset(cnt,0,sizeof(cnt)); 46 memset(ch,0,sizeof(ch)); 47 memset(c,0,sizeof(c)); 48 memset(fa,0,sizeof(fa)); 49 memset(l,0,sizeof(l)); 50 } 51 int main() 52 { 53 while(scanf("%d",&n)==1) 54 { 55 init(); 56 FOR(i,1,n) { 57 scanf("%s",s); 58 if(i!=1) add(10),len++; 59 for(int j=0;s[j];j++) 60 add(s[j]-'0'),len++; 61 } 62 FOR(i,1,sz) c[l[i]]++; 63 FOR(i,1,len) c[i]+=c[i-1]; 64 FOR(i,1,sz) b[c[l[i]]--]=i; 65 66 int ans=0; 67 cnt[1]=1; 68 FOR(i,1,sz) { 69 int p=b[i]; 70 for(int j=0;j<10;j++) { 71 if(i==1&&j==0) continue; 72 if(ch[p][j]) { 73 int np=ch[p][j]; 74 cnt[np]=(cnt[np]+cnt[p])%MOD; 75 sum[np]=(sum[np]+sum[p]*10+cnt[p]*j)%MOD; 76 } 77 } 78 ans=(ans+sum[p])%MOD; 79 } 80 printf("%d ",ans); 81 } 82 return 0; 83 }