#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个数串然后求出所有数串中所有子数串的sum
  • 如果一个一个的字串来求就要造n个自动机
  • 至于计算过程就是对于每一个节点延伸到下一个节点过程中将当前sum乘10之后加上到下一个节点的单个数乘以当前字串出现次数的乘积即可
  • 那么这样的计算方式没有问题但是建立n个SAM耗时太长了
  • 那么我们可不可以减少SAM的建立呢?
  • 还是可以的,只要把全部的字串用“:”链接,之后再建立SAM即可
  • 在这里我们总的计算方式是不变的
  • 但是对于一个出现过“:”的字串是不应该进行计算的,因为如果出现“:”就代表着当前字串包含至少两个原始串
  • 所以我们现在的问题是怎样辨别当前字串中是否出现过“:”
  • 我们可以通过在字串出现次数这里做文章,对于字串中出现“:”的我们可以通过把字串出现次数标记为0,在进行计算的过程中我们相当于没有对于当前待操作节点sum进行更新即可。那么这里对于cnt的计算可以通过普通的拓扑排序进行,在排序过程中只对于0到9的的路径进行记录
  • 之后就是从根节点进行一次bfs即可
  • 我的代码里把以上的cnt的计算和计算最终结果的bfs合并在一起了,用一个拓扑解决了

 

 

  1 #include <iostream>
  2 #include <string>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <algorithm>
  6 #include <climits>
  7 #include <cmath>
  8 #include <vector>
  9 #include <queue>
 10 #include <stack>
 11 #include <set>
 12 #include <map>
 13 using namespace std;
 14 typedef long long           LL ;
 15 typedef unsigned long long ULL ;
 16 const int    maxn = 1e6 + 10   ;
 17 const int    inf  = 0x3f3f3f3f ;
 18 const int    npos = -1         ;
 19 const LL     mod  = 1e9 + 7    ;
 20 const int    mxx  = 100 + 5    ;
 21 const double eps  = 1e-6       ;
 22 const double PI   = acos(-1.0) ;
 23 struct topo{
 24     int len, st;
 25     topo(int x, int y){
 26         len=x; st=y;
 27     }
 28 };
 29 bool topocmp(const topo &l, const topo &r){
 30     return l.len<r.len;
 31 }
 32 struct SAM{
 33     struct node{
 34         int len;
 35         int link, go[26];
 36         LL cnt, val;
 37     };
 38     node state[maxn<<1];
 39     int n, tot, root, last;
 40     void init(char *str){
 41         n=strlen(str);
 42         tot=1;
 43         root=1;
 44         last=1;
 45         memset(&state,0,sizeof(state));
 46         state[root].cnt=1LL;
 47     }
 48     void extend(int w){
 49         tot++;
 50         int p=last;
 51         int np=tot;
 52         state[np].len=state[p].len+1;
 53         state[np].cnt=0LL;
 54         // state[np].cnt=(w==10?1LL:0LL);
 55         state[np].val=0LL;
 56         while(p && state[p].go[w]==0){
 57             state[p].go[w]=np;
 58             p=state[p].link;
 59         }
 60         if(p==0){
 61             state[np].link=root;
 62         }else{
 63             int q=state[p].go[w];
 64             if(state[p].len+1==state[q].len){
 65                 state[np].link=q;
 66             }else{
 67                 tot++;
 68                 int nq=tot;
 69                 state[nq].len=state[p].len+1;
 70                 state[nq].cnt=state[q].cnt;
 71                 state[nq].val=0LL;
 72                 memcpy(state[nq].go,state[q].go,sizeof(state[q].go));
 73                 state[nq].link=state[q].link;
 74                 state[q].link=nq;
 75                 state[np].link=nq;
 76                 while(p && state[p].go[w]==q){
 77                     state[p].go[w]=nq;
 78                     p=state[p].link;
 79                 }
 80             }
 81         }
 82         last=np;
 83     }
 84     void build(char *str){
 85         init(str);
 86         for(int i=0;i<n;i++)
 87             extend(str[i]-'0');
 88     }
 89     LL calsum(void){
 90         LL ans=0LL;
 91         std::vector< topo > v;
 92         for(int i=root;i<=tot;i++)
 93             v.push_back(topo(state[i].len,i));
 94         sort(v.begin(),v.end(), topocmp);
 95         int sz=v.size(), p, q;
 96         for(int i=0;i<sz;i++){
 97             p=v[i].st;
 98             for(int j=0;j<10;j++)
 99                 if(state[p].go[j]){
100                     q=state[p].go[j];
101                     state[q].cnt+=state[p].cnt;
102                     state[q].val=(state[q].val + ((10LL*state[p].val)%mod + ((LL)j*state[p].cnt)%mod)%mod)%mod;
103                 }
104             ans=(ans+state[p].val)%mod;
105         }
106         ans=(ans+mod)%mod;
107         return ans;
108     }
109 };
110 SAM A;
111 int n, lth;
112 char str[maxn];
113 int main(){
114     // freopen("in.txt","r",stdin);
115     // freopen("out.txt","w",stdout);
116     while(~scanf("%d",&n)){
117         lth=0;
118         for(int i=1;i<=n;i++,lth++){
119             scanf("%s",str+lth);
120             lth=strlen(str);
121             if(i==n){break;}
122             str[lth]=':';
123         }
124         A.build(str);
125         printf("%lldn",A.calsum());
126     }
127     return 0;
128 }

 

内容来源于网络如有侵权请私信删除
你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!