hihocoder 1457 后缀自动机四·重复旋律7

时间限制:15000ms
单点时限:3000ms
内存限制:512MB
描述

小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一段音乐旋律可以被表示为一段数构成的数列。

神奇的是小Hi发现了一部名字叫《十进制进行曲大全》的作品集,顾名思义,这部作品集里有许多作品,但是所有的作品有一个共同特征:只用了十个音符,所有的音符都表示成0-9的数字。

现在小Hi想知道这部作品中所有不同的旋律的“和”(也就是把串看成数字,在十进制下的求和,允许有前导0)。答案有可能很大,我们需要对(10^9 + 7)取摸。

解题方法提示

输入

第一行,一个整数N,表示有N部作品。

接下来N行,每行包含一个由数字0-9构成的字符串S。

所有字符串长度和不超过 1000000。

输出

共一行,一个整数,表示答案 mod (10^9 + 7)。

样例输入
2
101
09
样例输出
131

这题我用的方法比较神奇,由于是要考虑在这n个串里面的不同串,所以我们按照很多后缀数组的做法,在每个字符串的后面加上一个额外的字符(这里是编号为58的字符),然后把他们连接起来,对连接后的字符串建立后缀自动机。然后预处理val[i]表示s[i]..s[len]组成十进制数以后的结果,sum[i]=sum[i+1]+val[i],同时预处理$10^{k}$关于mod $10^{9}+7$的逆元。于是,我们可以枚举sam上每个节点,利用前面的3个数组计算出每个节点里面不同字符串构成的和,注意计算的时候要剔除那个58字符的影响。

 1 #include<bits/stdc++.h>
 2 using namespace std;  
 3 #define LL  long long 
 4 int const N=2000000+100;  
 5 int const mod=1e9+7;   
 6 struct node{
 7     int len,fa,ch[11];  
 8 }a[N<<1];  
 9 int n,pw[N],sum[N],ans,inv[N],sz[N<<1],tot,ls,w[N<<1],num[N],sa[N<<1],vis[N],lc[N];   
10 char s[N],s1[N];   
11 LL val[N];   
12 void add(int c,int id){
13     int p=ls;  
14     int np=ls=++tot;  
15     w[np]=id;  
16     a[np].len=a[p].len+1;  
17     sz[np]=1; 
18     for(;p && !a[p].ch[c]; p=a[p].fa) a[p].ch[c]=np;  
19     if(!p) a[np].fa=1; 
20     else {
21         int q=a[p].ch[c];  
22         if(a[q].len==a[p].len+1) a[np].fa=q; 
23         else {
24             int nq=++tot;  
25             a[nq]=a[q];  
26             a[nq].len=a[p].len+1;  
27             a[q].fa=a[np].fa=nq;  
28             for(;p&&a[p].ch[c]==q;p=a[p].fa) a[p].ch[c]=nq;  
29         } 
30     } 
31 } 
32 inline LL ksm(LL n,LL  m,LL  mod){
33     LL  ans=1; 
34     while (m){
35         if(m&1) ans=ans*n % mod;  
36         n=n*n % mod;  
37         m>>=1; 
38     }  
39     return ans; 
40 }  
41 int main(){
42     pw[0]=1;  
43     for(int i=1;i<=2000000;i++)  pw[i]=1LL*pw[i-1]*10 % mod;   
44     for(int i=0;i<=2000000;i++)  inv[i]=ksm(pw[i],mod-2,mod);  
45     scanf("%d",&n);  
46     LL ans=0; 
47     int len=0;   
48     while (n--){
49         scanf("%s",s1);  
50         strcat(s+1,s1);    
51         len+=strlen(s1);  
52         s[++len]=58; 
53         vis[len]=1;  
54     }   
55     for(int i=1;i<=len;i++)  
56         if(vis[i]) lc[i]=i;  
57         else lc[i]=lc[i-1];  
58     tot=ls=1;                 
59     for(int i=1;i<=len;i++) 
60         add(s[i]-48,i);  
61     LL t=0;  
62     for(int i=len;i>=1;i--){
63         t=(1LL*(s[i]-48)*pw[len-i]+t) % mod;    
64         sum[i]=(sum[i+1]+t) % mod; 
65         val[i]=t;     
66     }       
67     for(int i=1;i<=len;i++) num[i]=0;  
68     for(int i=1;i<=tot;i++) num[a[i].len]++;  
69     for(int i=1;i<=len;i++) num[i]+=num[i-1]; 
70     for(int i=1;i<=tot;i++) sa[num[a[i].len]--]=i;  
71     for(int i=tot;i>=1;i--){
72         int x=sa[i],f=a[x].fa; 
73         sz[f]+=sz[x];      
74         w[f]=w[f]? w[f]: w[x]; 
75     } 
76     for(int i=2;i<=tot;i++) { 
77         if(vis[w[i]]) continue; 
78         int cnt=a[i].len-a[a[i].fa].len;   
79         int y=w[i]-a[a[i].fa].len;    
80         int x=y-cnt+1;                
81         if(y<=    lc[w[i]]) continue;  
82         if(lc[w[i]]>=x)  x=lc[w[i]]+1; 
83         cnt=y-x+1;      
84         LL  v=( (sum[x]-sum[y+1]) % mod+ mod ) % mod;       
85         v=( (v-cnt*val[w[i]+1]) % mod + mod ) % mod *inv[len-w[i]] % mod;
86         ans=(ans+v) % mod;  
87     }  
88     cout<<ans<<endl;         
89     return 0; 
90 }                   
View Code

 

posted @ 2019-06-17 21:37  zjxxcn  阅读(164)  评论(0编辑  收藏  举报