题意:给出n个数字,数字很长,用字符串读入,长度总和为10^5。求这n个字符串的所有子串(不重复)的和取模2012 。
例如字符串101,和就是1+10+101=112。
题解:
就是求不同的子串连成一个数。
sam的拓扑序真的很有用!按拓扑序可以保证能转移到当前x的节点都在之前被更新了。
每个节点x维护cnt表示root到x的方案数,sum表示以x为结尾的子串和。
找拓扑序有两种方法:1.拓扑排序一样bfs(O(n)) 2.按照step[x]排序(若x有个孩子是y,step[x]<=step[y](O(nlogn))
按照拓扑序for一遍,对于x,它的孩子y,cnt[y]+=cnt[x],sum[y]+=sum[x]*10+cnt[x]*(y所代表的数字)。
不能有前缀0----->根节点不走0孩子。
节点数开了10^6才AC。tell me why?!
打了两种求拓扑序的方法。
贴一下代码。
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<iostream>
5 #include<queue>
6 #include<ctime>
7 #include<algorithm>
8 using namespace std;
9
10 const int N=10*100010,Mod=2012;
11 char s[N];
12 int n,sl,cl,ans,tot,last;
13 int son[N][30],pre[N],step[N],sum[N],in[N],cnt[N],c[N];
14 bool vis[N];
15 queue<int> Q;
16
17 int add_node(int x)
18 {
19 step[++tot]=x;
20 return tot;
21 }
22
23 void extend(int ch)
24 {
25 int p=last,np=add_node(step[last]+1);
26 while(p && !son[p][ch]) son[p][ch]=np,in[np]++,p=pre[p];
27 if(!p) pre[np]=1;
28 else
29 {
30 int q=son[p][ch];
31 if(step[q]==step[p]+1) pre[np]=q;
32 else
33 {
34 int nq=add_node(step[p]+1);
35 memcpy(son[nq],son[q],sizeof(son[q]));
36 for(int i=0;i<=9;i++)
37 if(son[q][i]) in[son[q][i]]++;
38 pre[nq]=pre[q];
39 pre[np]=pre[q]=nq;
40 while(son[p][ch]==q) in[q]--,in[nq]++,son[p][ch]=nq,p=pre[p];
41 }
42 }
43 last=np;
44 }
45
46 void find_tp_1()
47 {
48 for(int i=2;i<=tot;i++)
49 {
50 if(in[i]==0)
51 {
52 for(int j=0;j<=9;j++)
53 {
54 int y=son[i][j];
55 if(!y) continue;
56 in[y]--;
57 }
58 }
59 }
60 while(!Q.empty()) Q.pop();
61 Q.push(1);vis[1]=1;cl=0;
62 while(!Q.empty())
63 {
64 int x=Q.front();vis[x]=0;c[++cl]=x;Q.pop();
65 for(int i=0;i<=9;i++)
66 {
67 int y=son[x][i];
68 if(!y) continue;
69 in[y]--;
70 if(!in[y] && !vis[y]) vis[y]=1,Q.push(y);
71 }
72 }
73 }
74
75 bool cmp(int x,int y){return step[x]<step[y];}
76 void find_tp_2()
77 {
78 cl=0;
79 for(int i=1;i<=tot;i++)
80 {
81 if(in[i] || i==1) c[++cl]=i;
82 }
83 sort(c+1,c+1+cl,cmp);
84 }
85
86 void solve()
87 {
88 cnt[1]=1;
89 for(int i=1;i<=cl;i++)
90 {
91 int x=c[i];
92 for(int j=0;j<=9;j++)
93 {
94 int y=son[x][j];
95 if(!y || (x==1 && j==0)) continue;
96 cnt[y]=(cnt[y]+cnt[x])%Mod;
97 sum[y]=(sum[y]+(sum[x]*10)%Mod+(j*cnt[x])%Mod)%Mod;
98 }
99 }
100 }
101
102 int main()
103 {
104 freopen("a.in","r",stdin);
105 // freopen("me.out","w",stdout);
106 while(scanf("%d",&n)!=EOF)
107 {
108 memset(son,0,sizeof(son));
109 memset(step,0,sizeof(step));
110 memset(pre,0,sizeof(pre));
111 memset(in,0,sizeof(in));
112 memset(cnt,0,sizeof(cnt));
113 memset(sum,0,sizeof(sum));
114 tot=0;add_node(0);last=1;
115 for(int i=1;i<=n;i++)
116 {
117 scanf("%s",s+1);
118 sl=strlen(s+1);
119 last=1;
120 for(int j=1;j<=sl;j++) extend(s[j]-'0');
121 }
122 find_tp_1();//找拓扑序方法一 : bfs=拓扑排序
123 // find_tp_2();//方法二:直接对step[x]进行排序
124 solve();
125 ans=0;
126 for(int i=1;i<=tot;i++) ans=(ans+sum[i])%Mod;
127 printf("%d
",ans);
128 // cout<<"Time Used : "<<(double)clock()/CLOCKS_PER_SEC<<" s."<<endl;
129 }
130 return 0;
131 }