题意:给出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\n",ans); 128 // cout<<"Time Used : "<<(double)clock()/CLOCKS_PER_SEC<<" s."<<endl; 129 } 130 return 0; 131 }
时间: 2024-10-20 18:33:36