hihocoder 1457(后缀自动机+拓扑排序)
Posted Saurus
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hihocoder 1457(后缀自动机+拓扑排序)相关的知识,希望对你有一定的参考价值。
题意
给定若干组由数字构成的字符串,求所有不重复子串的和(把他们看成十进制),答案mod(1e9+7)
题解:
类似后缀数组的做法,把字符串之间用‘:‘连接,这里用‘:‘是因为‘:‘的ascii码恰好是9的下一个
然后建立后缀自动机。
之后把其实只要把其中的所有‘:‘边删去,就可以进行转移了
如果x连向了y,边权是c,那么有转移
dp[y] += dp[x]*10 + c*sz[x]
所以只要拓扑排序一下就好
(写这题wa了好几次,主要是在删边建立新图的过程出了问题)
#include <iostream> #include <cstring> #include <cstdio> #include <queue> using namespace std; typedef long long LL; int n = 0, len, st; const int maxL = 2e6 + 100; const int MOD = 1e9 + 7; int maxlen[2*maxL], minlen[2*maxL], trans[2*maxL][12], slink[2*maxL], col[2*maxL]; LL in[2*maxL], dp[2*maxL], sz[2*maxL]; int new_state(int _maxlen, int _minlen, int *_trans, int _slink){ maxlen[n] = _maxlen; minlen[n] = _minlen; for(int i = 0; i < 11; i++){ if(_trans == NULL) trans[n][i] = -1; else trans[n][i] = _trans[i]; } slink[n] = _slink; return n++; } int add_char(char ch, int u){ int c = ch - ‘0‘; int z = new_state(maxlen[u]+1, -1, NULL, -1); int v = u; while(v != -1 && trans[v][c] == -1){ trans[v][c] = z; v = slink[v]; } if(v == -1){ minlen[z] = 1; slink[z] = 0; return z; } int x = trans[v][c]; if(maxlen[v] + 1 == maxlen[x]){ minlen[z] = maxlen[x] + 1; slink[z] = x; return z; } int y = new_state(maxlen[v] + 1, -1, trans[x], slink[x]); slink[y] = slink[x]; minlen[x] = maxlen[y] + 1; slink[x] = y; minlen[z] = maxlen[y] + 1; slink[z] = y; int w = v; while(w != -1 && trans[w][c] == x){ trans[w][c] = y; w = slink[w]; } minlen[y] = maxlen[slink[y]] + 1; return z; } char str[maxL]; queue<int> Q; int main() { freopen("a.txt", "r", stdin); int N; cin>>N; st = new_state(0, 0, NULL, -1); while(N--){ cin>>str; int len = strlen(str); for(int i = 0; i < len; i++) { st = add_char(str[i], st); } st = add_char(‘:‘, st); } Q.push(0); col[0] = 1; while(!Q.empty()){ int x = Q.front(); Q.pop(); for(int c = 0; c < 10; c++){ int y = trans[x][c]; if(y == -1) continue; if(!col[y]) Q.push(y); col[y] = 1; in[y]++; } } Q.push(0); sz[0] = 1; while(!Q.empty()){ int x = Q.front(); Q.pop(); for(int c = 0; c < 10; c++){ int y = trans[x][c]; if(y == -1) continue; in[y]--; if(in[y] == 0) Q.push(y); (sz[y] += sz[x]) %= MOD; (dp[y] += dp[x]*10 + c*sz[x]) %= MOD; } } LL ans = 0; /* for(int i = 0; i < n; i++){ for(int c = 0; c < 10; c++){ if(trans[i][c] == -1) continue; cout<<i<<" "<<trans[i][c]<<" "<<c<<endl; } }*/ //for(int i = 0; i < n; i++) cout<<dp[i]<<" "; cout<<endl; for(int i = 0; i < n; i++) (ans += dp[i]) %= MOD; cout<<ans<<endl; return 0; }
以上是关于hihocoder 1457(后缀自动机+拓扑排序)的主要内容,如果未能解决你的问题,请参考以下文章
hihocoder #1457 : 后缀自动机四·重复旋律7