码迷,mamicode.com
首页 > 其他好文 > 详细

hihocoder 1457 后缀自动机四·重复旋律7 求不同子串的和

时间:2018-03-08 22:05:08      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:print   inpu   不重复   for   数字   empty   get   个数   现在   

描述

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

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

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

解题方法提示

输入

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

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

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

输出

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

Sample Input

2
101
09

Sample Output

131

  1 #include<cstring>
  2 #include<cmath>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<queue>
  6 #include<iostream>
  7 
  8 #define ll long long
  9 #define N 3000007
 10 #define mod 1000000007
 11 using namespace std;
 12 inline int read()
 13 {
 14     int x=0,f=1;char ch=getchar();
 15     while(!isdigit(ch)){if(ch==-)f=-1;ch=getchar();}
 16     while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-0;ch=getchar();}
 17     return x*f;
 18 }
 19 
 20 int n;
 21 struct sam
 22 {
 23     int last,cnt;
 24     int c[N][11],fa[N],mx[N],flag[N];
 25     sam(){last=cnt=1;}
 26     void extend(int x)
 27     {
 28         int p=last,np=last=++cnt;mx[np]=mx[p]+1;
 29         if(x==10)flag[np]=1;
 30         while(p&&!c[p][x])
 31         {
 32             c[p][x]=np;
 33             p=fa[p];
 34         }
 35         if(!p)fa[np]=1;
 36         else
 37         {
 38             int q=c[p][x];
 39             if(mx[q]==mx[p]+1)fa[np]=q;
 40             else
 41             {
 42                 int nq=++cnt;mx[nq]=mx[p]+1;
 43                 memcpy(c[nq],c[q],sizeof(c[q]));
 44                 fa[nq]=fa[q];
 45                 fa[q]=fa[np]=nq;
 46                 while(c[p][x]==q)c[p][x]=nq,p=fa[p];
 47                 if(x==10)flag[nq]=1;
 48             }
 49         }
 50     }
 51     int du[N],num[N];
 52     void init()
 53     {
 54         /*for (int i=1;i<=cnt;i++)
 55         {
 56             for (int j=0;j<=10;j++)
 57                 if(c[i][j])cout<<c[i][j]<<" ";
 58             cout<<endl;
 59         }*/
 60         for (int i=1;i<=cnt;i++)
 61             for (int j=0;j<=10;j++)
 62                 if(c[i][j])du[c[i][j]]++;
 63         num[1]=1;
 64     }
 65     int now,pre;queue<int>q[2];
 66     ll sum[N];
 67     void solve()
 68     {
 69         pre=0,now=1;
 70         for (int i=1;i<=cnt;i++)
 71             if(!du[i])q[pre].push(i);
 72         while(!q[pre].empty())
 73         {
 74             while(!q[pre].empty())
 75             {
 76                 int x=q[pre].front();q[pre].pop();
 77                 if(flag[x])sum[x]=0;
 78                 for (int i=0;i<=10;i++)
 79                     if(c[x][i])
 80                     {
 81                     //    if(c[x][i]==10)cout<<"fack="<<x<<" "<<c[x][i]<<endl;
 82                         if (!flag[x])
 83                         {
 84                             num[c[x][i]]+=num[x];
 85                             (sum[c[x][i]]+=sum[x]*10+num[x]*i)%=mod;
 86                         }
 87                         du[c[x][i]]--;
 88                         if(!du[c[x][i]])q[now].push(c[x][i]);
 89                     }
 90             }
 91             swap(now,pre);
 92         }
 93         /*for (int i=1;i<=cnt;i++)
 94             cout<<sum[i]<<endl;*/
 95         ll ans=0;
 96         for (int i=1;i<=cnt;i++)
 97             (ans+=sum[i])%=mod;
 98         printf("%lld\n",ans);
 99     }
100 }sam;
101 char s[1000007];
102 
103 int main()
104 {
105     n=read();
106     for (int i=1;i<=n;i++)
107     {
108         scanf("%s",s+1);int len=strlen(s+1);
109         for (int j=1;j<=len;j++)
110             sam.extend(s[j]-0);
111         if(i<n)sam.extend(10);
112     }
113     sam.init();
114     sam.solve();
115 }

 

hihocoder 1457 后缀自动机四·重复旋律7 求不同子串的和

标签:print   inpu   不重复   for   数字   empty   get   个数   现在   

原文地址:https://www.cnblogs.com/fengzhiyuan/p/8531028.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!