POJ 2778 DNA Sequence && AC自动机 矩阵 矩阵加速
2013-10-14 21:02
309 查看
暑假刚学完AC自动机模板的时候,看见这道题就感觉这题好难,经过几次复习与学习,突然发现这题不是那么的难。
题意:给你10个只由‘A’、‘T’、‘C’、‘G’这四个字母组成的最大长度为10的字符串。问有多少个不同的长度为n (1 <= n <=2000000000).的字符串。结果对100000取余。
解法:之前做的都是状压DP,见到这题也想这么做,突然发现长度略大,DP一定TLE。由于数据量是10^9,本能反应就是log(n)算法,看那众多大神的题解,学习到,原来矩阵也可以这么用。先是做一个AC自动机,然后做状态转移矩阵:枚举每一个节点,然后让这个节点添加一个字母(A、T、C、G)判断是不是单词节点,如果不是就把矩阵的对应位置++;如果是单词节点,那么就寻找适配路径之前的节点,同上处理。最后就能得到一个“节点数*节点数”大小的矩阵,每个位置代表从某个状态转移到另一个状态的方案数。最后求矩阵的n次方,需要矩阵加速,也就是快速幂的思路。
题意:给你10个只由‘A’、‘T’、‘C’、‘G’这四个字母组成的最大长度为10的字符串。问有多少个不同的长度为n (1 <= n <=2000000000).的字符串。结果对100000取余。
解法:之前做的都是状压DP,见到这题也想这么做,突然发现长度略大,DP一定TLE。由于数据量是10^9,本能反应就是log(n)算法,看那众多大神的题解,学习到,原来矩阵也可以这么用。先是做一个AC自动机,然后做状态转移矩阵:枚举每一个节点,然后让这个节点添加一个字母(A、T、C、G)判断是不是单词节点,如果不是就把矩阵的对应位置++;如果是单词节点,那么就寻找适配路径之前的节点,同上处理。最后就能得到一个“节点数*节点数”大小的矩阵,每个位置代表从某个状态转移到另一个状态的方案数。最后求矩阵的n次方,需要矩阵加速,也就是快速幂的思路。
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<cmath> #include<vector> #define inf 0x3f3f3f3f #define Inf 0x3FFFFFFFFFFFFFFFLL #define pi acos(-1.0) #define eps 1e-8 using namespace std; const int maxnode = 110; const int charsize = 4; const int mod = 100000; int ch[maxnode][charsize], f[maxnode], val[maxnode], last[maxnode]; int sz, n, m; void init() {memset(ch[0],0,sizeof ch[0]);sz=1;} int idx(char c) {if(c=='A') return 0; if(c=='T') return 1; if(c=='C') return 2; return 3;} void insert(char *s, int v = 1) { int u = 0, n = strlen(s); for(int i = 0 ; i < n ; ++ i) { int c = idx(s[i]); if(!ch[u][c]) { memset(ch[sz],0,sizeof ch[sz]); val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } val[u] = v; } void getfail() { queue<int> q; f[0] = 0; for(int c = 0 ; c < charsize ; ++ c) { int u = ch[0][c]; if(u) {f[u]=last[u]=0;q.push(u);} } while(!q.empty()) { int r = q.front(); q.pop(); for(int c = 0 ; c < charsize ; ++ c) { int u = ch[r][c]; if(!u) { ch[r][c] = ch[f[r]][c];continue;} q.push(u); int v = f[r]; while(v&&!ch[v][c]) v = f[v]; f[u] = ch[v][c]; last[u] = val[f[u]]?f[u]:last[f[u]]; } } } struct mat { long long m[maxnode][maxnode]; mat operator*(const mat& ma) const { mat c; memset(c.m, 0, sizeof c.m); for(int i = 0 ; i < sz ; ++ i) { for(int j = 0 ; j < sz ; ++ j) { for(int k = 0 ; k < sz ; ++ k) { c.m[i][j] += m[i][k]*ma.m[k][j]; } if(c.m[i][j]>=mod) c.m[i][j]%=mod; } } return c; } }g; mat pow(mat m, int n) { mat tmp; for(int i = 0 ; i < sz ; ++ i) { for(int j = 0 ; j < sz ; ++ j) { tmp.m[i][j] = (i==j); } } while(n) { if(n&1) tmp = tmp*m; m = m*m; n>>=1; } return tmp; } int main() { //freopen("in.txt","r",stdin); while(~scanf("%d%d",&n,&m)) { char s[maxnode]; init(); for(int i = 0 ; i < n ; ++ i) { scanf("%s",s); insert(s); } getfail(); for(int i = 0 ; i < sz ; ++ i) { if(val[i]||last[i]) continue; for(int c = 0 ; c < charsize ; ++ c) { int u = ch[i][c]; if(u) { if(!val[u]&&!last[u]) g.m[i][u] ++; } else { int t = f[i]; while(t) { int u = ch[t][c]; if(u&&!val[u]&&!last[u]) { g.m[i][u]++; break; } t = f[t]; } if(t==0) { int u = ch[t][c]; if(!u&&!val[u]&&!last[u]) g.m[i][u]++; else if(!u) g.m[i][0]++; } } } } mat tt = pow(g, m); long long ans = 0; for(int i = 0 ; i < sz ; ++ i) { ans += tt.m[0][i]; ans%=mod; } printf("%I64d\n",ans); } return 0; }
相关文章推荐
- poj 2778 DNA Sequence 【AC自动机 + 矩阵加速】
- poj -- 2778 DNA Sequence && hdu -- 2243 考研路茫茫——单词情结(AC自动机 + 矩阵)
- POJ 2778 DNA Sequence [AC自动机 矩阵乘法]
- POJ 2778 DNA Sequence [AC自动机 + 矩阵快速幂]
- poj2778.DNA Sequence (Trie图 && 矩阵乘)
- POJ 2778 DNA Sequence (AC自动机,矩阵乘法)
- POJ 2778 DNA Sequence [AC自动机 + 矩阵快速幂]
- poj 2778 DNA Sequence 【ac自动机 + dp + 矩阵快速幂】
- POJ 2778 - DNA Sequence (AC自动机 矩阵快速幂)
- POJ 2778 DNA Sequence(AC自动机 + 矩阵乘法)
- POJ - 2778_DNA Sequence_AC自动机&&矩阵快速幂
- POJ 题目2778 DNA Sequence(AC自动机,矩阵快速幂)
- POJ 2778 DNA Sequence (AC自动机+矩阵加速,4级)
- POJ 2778 DNA Sequence (AC自动机+矩阵加速,4级)
- poj 2778 DNA Sequence(AC自动机 + 矩阵快速幂)
- POJ 2778 DNA Sequence (AC自动机 + 矩阵快速幂)
- POJ2778 DNA sequence[自动AC机&矩阵快速幂]
- POJ 2778 DNA Sequence(自动机+矩阵DP)
- POJ 2778 DNA Sequence(自动机+矩阵)
- 【POJ 2778】DNA Sequence 中文题意&题解&代码(C++)