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 }