hiho一下第130周 后缀自动机二·重复旋律7
后缀自动机四·重复旋律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
#include <iostream> #include <cstring> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <time.h> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int N=2e6+100; const int M=1e6+5; const long long MOD = 1000000007LL; int tot,slink[2*N],trans[2*N][26],minlen[2*N],maxlen[2*N],edpts[2*N]; string str; int n; int containPrefix[N],ind[N],ans[2*N+10],cnt[N*2]; ll sum[N*2],sz_valid[N*2]; int newstate(int _maxlen,int _minlen,int* _trans,int _slink) { maxlen[++tot]=_maxlen; minlen[tot]=_minlen; slink[tot]=_slink; if(_trans) for(int i=0; i<11; i++) trans[tot][i]=_trans[i]; return tot; } int add_char(char ch,int u) { int c=ch-'0',v=u; int z=newstate(maxlen[u]+1,-1,NULL,0); containPrefix[z]=1; while(v&&!trans[v][c]) { trans[v][c]=z; v=slink[v]; } if(!v) { minlen[z]=1; slink[z]=1; ind[0]++; return z; } int x=trans[v][c]; if(maxlen[v]+1==maxlen[x]) { slink[z]=x; minlen[z]=maxlen[x]+1; ind[x]++; return z; } int y=newstate(maxlen[v]+1,-1,trans[x],slink[x]); slink[z]=slink[x]=y; ind[y]+=2; minlen[x]=minlen[z]=maxlen[y]+1; while(v&&trans[v][c]==x) { trans[v][c]=y; v=slink[v]; } minlen[y]=maxlen[slink[y]]+1; return z; } void init_dag() { for ( int i = 0; i <=tot; i++ ) { for ( int j = 0; j < 11; j++ ) { if ( trans[i][j] > 0 ) { cnt[trans[i][j]] ++; } } } } void topsort(){ queue<int>q; for ( int i = 1; i <=tot; i++ ) { if ( cnt[i] == 0 ) { q.push(i); sz_valid[i] = 1; sum[i] = 0; } } while(!q.empty()){ int i=q.front(); q.pop(); for ( int k = 0; k < 11; k++ ) { if ( trans[i][k] >0 ) { int j = trans[i][k]; if(k < 10) { sz_valid[j] += sz_valid[i]; sz_valid[j] %= MOD; sum[j] += sum[i] * 10 + k * sz_valid[i]; sum[j] %= MOD; } cnt[j] --; if(cnt[j] == 0) q.push(j); } } } } int main() { cin>>n; cin>>str; for(int i=1;i<n;i++){ string ss; cin>>ss; str=str+":"+ss; } int pre=newstate(0,0,NULL,-1);; tot=1; int len=str.length(); for(int i=0; i<len; i++) { pre=add_char(str[i],pre); } init_dag(); topsort(); ll ans=0; for ( int i = 1; i <=tot; i++ ) { ans += sum[i]; ans %= MOD; } cout << ans << endl; return 0; }