poj 2778 AC自己主动机 + 矩阵高速幂
Posted gccbuaa
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj 2778 AC自己主动机 + 矩阵高速幂相关的知识,希望对你有一定的参考价值。
// poj 2778 AC自己主动机 + 矩阵高速幂 // // 题目链接: // // http://poj.org/problem?id=2778 // // 解题思路: // // 建立AC自己主动机,确定状态之间的关系,构造出,走一步 // 能到达的状态矩阵,然后进行n次乘法,就能够得到状态间 // 走n步的方法数. // 精髓: // 1):这个ac自己主动机有一些特别,根节点是为空串,然而 // 每走一步的时候,假设没法走了,这时候,不一定是回到根 // 节点,由于有可能单个的字符时病毒,这样,不是随便就能达到 // 所谓的根节点的,所以每次初始化的时候,不能是0,而应该是 // -1. // // 感悟: // // 这道AC自己主动机,開始我是全然不会,知道是AC自己主动机+矩阵高速幂 // 開始,自以为AC自己主动机构造的非常对,并且例子都过了好嘛,结果一直是 // wrong answer.我就不信邪了,肯定是博主博客有错误,我就将博主的 // 交了一发,然而,博主的过了,我的没过.哎,一阵伤心,但心里也是再次 // 燃起了希望之火,还是能够搞得.然而我就细致研究,对拍呗,自己造了 // 几个例子.发现以下这组: // 4 2 // A // C // T // GT // 这组例子,答案应该是1,而我的答案是3.我仿佛一下子恍然大悟,发现 // 单个字符是病毒,不能走回根节点.明确了过后,一改,就AC了,尽管速度 // 有点慢,可是我发现自己对AC自己主动机的理解又有了一点小小的新的拓展 // 尽管作为菜鸟的我敢于怀疑是一件好事,可是自己的不正确就是不正确,不要 // 由于自己的自信就去刻意寻找别人的错误,觉得别人是错误的.有着一颗 // 敢于承认错误,并且接受正确观念,并明悟的人,我觉得光明,就在前方! #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <queue> using namespace std; typedef long long ll; const int MAX_NODE = 110; const ll MOD = 100000; const int MAX_N = 110; struct Matrix{ ll mat[MAX_N][MAX_N]; }res; int n,m; struct Aho_Corasick{ int ch[MAX_NODE][4]; bool val[MAX_NODE]; int f[MAX_NODE]; //int last[MAX_NODE]; int sz; void init(){ memset(ch[0],-1,sizeof(ch[0])); val[0] = 0; sz = 1; f[0] = 0; //last[0] = 0; } 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 u = 0; int n = strlen(s); for (int i=0;i<n;i++){ int c = idx(s[i]); if (ch[u][c]==-1){ memset(ch[sz],-1,sizeof(ch[sz])); val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } val[u] = true; } void getfail(){ queue<int> que; f[0] = 0; for (int c = 0;c < 4;c++){ int u = ch[0][c]; if (u!=-1){ que.push(u); f[u] = 0; // last[u] = 0; }else{ ch[0][c] = 0; //表示当此c单个字符不是病毒的时候,则能够走回根 } } while(!que.empty()){ int r = que.front(); que.pop(); if (val[f[r]]) // 当r的某个后缀为病毒的时候标记此r val[r] = true; for (int c = 0; c < 4;c++){ int u = ch[r][c]; if (u == -1){ ch[r][c] = ch[f[r]][c]; //把不存在的边接上去 continue; } que.push(u); int v = f[r]; while(v && ch[v][c]==-1) v = f[v]; f[u] = ch[v][c]; //last[u] = val[f[u]] ? f[u] : last[f[u]]; } } } void get_matrix(){ memset(res.mat,0,sizeof(res.mat)); for (int u=0;u<sz;u++){ for (int c = 0;c < 4;c++){ if (!val[u] && !val[ch[u][c]]) res.mat[u][ch[u][c]]++; } } } }ac; Matrix Mulity(Matrix a,Matrix b){ Matrix ans; for (int i=0;i < ac.sz;i++) for (int j=0;j < ac.sz;j++){ ans.mat[i][j] = 0; for (int k=0;k < ac.sz ;k++) ans.mat[i][j] = (ans.mat[i][j] + a.mat[i][k] * b.mat[k][j])%MOD; ans.mat[i][j] %= MOD; } return ans; } Matrix Matrix_power(Matrix a,int b){ Matrix ans; memset(ans.mat,0,sizeof(ans.mat)); for (int i=0;i<ac.sz;i++) ans.mat[i][i] = 1; while(b){ if (b & 1) ans = Mulity(ans,a); a = Mulity(a,a); b >>=1; } return ans; } void print(Matrix r){ for (int i=0;i<ac.sz;i++){ for (int j=0;j<ac.sz;j++) cout << r.mat[i][j] << " "; cout << endl; } } void input(){ ac.init(); char s[20]; for (int i=1;i<=m;i++){ scanf("%s",s); ac.insert(s); } ac.getfail(); ac.get_matrix(); // print(res); res = Matrix_power(res,n); // cout << endl; // print(res); ll ans = 0; for (int i=0;i<ac.sz;i++){ ans = (ans + res.mat[0][i])%MOD; } cout << ans%MOD << endl; } int main(){ //freopen("1.txt","r",stdin); while(scanf("%d%d",&m,&n)!=EOF){ // puts("-------"); input(); } return 0; }
以上是关于poj 2778 AC自己主动机 + 矩阵高速幂的主要内容,如果未能解决你的问题,请参考以下文章
POJ 1625 Censored! (AC自己主动机 + 高精度 + DP)
poj 2778 DNA Sequence ac自动机+矩阵快速幂
POJ 2778 DNA Sequence(AC自动机+矩阵)
poj 2778 DNA Sequence(ac自动机+矩阵快速幂)