// hdu 2243 AC自动机 + 矩阵快速幂 // // 题目大意: // // 给你一些短串,问在长度不超过k的任意串,包含至少一个这些短串的其中 // 一个.问这样的串有多少个. // // 解题思路: // // 首先, 包含和不包含是一种互斥关系,包含+不包含 = 全集u.全集的答案就是 // 26 ^ 1 + 26 ^ 2 + .... + 26 ^ k.不包含的比较好求.构建一个自动机,得到 // 一个转移矩阵A.表示状态i能到状态j的方法数.而这些状态中都是不包含所给的 // 串的.我们对这个矩阵进行k次幂,得到的矩阵的第一行的和,就是长度为k的不包 // 含串的的总数.我们要求的是A + A ^ 2 + A ^ 3 +.... + A ^ k.之后的部分就是 // 矩阵的再次构造.对于矩阵 | A E | // // | 0 E | 对其求n次方,得到 // // | A^n 1 + A + A^2 +...+A^(n-1) | // | 0 E | // 对于这一题,我们增加一维构成全是1.即列全是1,行全是0除了处在最后一列上的除外. // 对于26是一样的求法即 | 26 1 | // | 0 1 | 对其求n次方,得到 // // | 26^n 1 + 26 + 26 ^ 2 + ... + 26^(n-1)| // | 0 1 | // 这样最后的答案就是全集 - 不包含.(矩阵写的搓,望各位体谅一二 (^ - ^) // // 感悟: // // 这道题,重点的思维还是在于补集的思想.将不好求的问题转化为好求的问题.自动机的 // 构建通过poj2778已经经历了一定程度的锤炼,不成问题.矩阵的构造也是问题不大,关键 // 是矩阵的n次方的求和.本来有一道裸地矩阵n次方求和,兴奋的学了学大牛的二分思想, // 结果爆栈了,加了扩充栈以后,tle了...好吧,乖乖地再次构造一个矩阵,添加一维,然后 // 就过了,瞬间觉得矩阵太美妙了~~~~总的来说,这道题还是不错的,继续加油吧~~~FIGHTING //#pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <algorithm> #include <iostream> #include <cstring> #include <queue> using namespace std; typedef unsigned long long ull; const int MAX_N = 66; const int SIGMA = 26; //;const ull MOD = (ull)1 << 64; struct Matrix { int r,c; ull mat[MAX_N][MAX_N]; }res; struct Aho_Corasick{ int ch[MAX_N][SIGMA]; int f[MAX_N]; int last[MAX_N];; bool val[MAX_N]; int sz; void init(){ memset(ch[0],-1,sizeof(ch[0])); f[0] = 0; last[0] = 0; sz = 1; } int idx(char c){ return c - 'a'; } void insert(char *s){ int n = strlen(s); int u = 0; 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; for (int c=0;c<SIGMA;c++){ int u = ch[0][c]; if (u!=-1){ que.push(u); f[u] = 0; last[u] = 0; } else { ch[0][c] = 0; } } while(!que.empty()){ int r = que.front(); que.pop(); if (val[f[r]]) val[r] = true; for (int c = 0;c < SIGMA;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 < 26; c++){ if (!val[u] && !val[ch[u][c]]) res.mat[u][ch[u][c]]++; } } for (int i=0;i<sz+1;i++) res.mat[i][sz]=1; res.r = sz + 1; res.c = sz + 1; //print(); } }ac; int n,l; Matrix Multiply(Matrix a,Matrix b){ Matrix ans; for (int i=0;i<a.r;i++) for (int j=0;j<b.c;j++){ ans.mat[i][j] = 0; for (int k=0;k<a.c;k++) ans.mat[i][j] += a.mat[i][k] * b.mat[k][j]; } ans.r = a.r; ans.c = b.c; return ans; } Matrix Add(Matrix a,Matrix b){ for (int i=0;i<a.r;i++) for (int j=0;j<a.c;j++) a.mat[i][j] += b.mat[i][j]; return a; } Matrix Power(Matrix a,int b){ Matrix ans; ans.r = a.r; ans.c = a.c; memset(ans.mat,0,sizeof(ans.mat)); for (int i=0;i<a.r;i++) ans.mat[i][i] = 1; while(b){ if (b & 1) ans = Multiply(ans,a); a = Multiply(a,a); b>>=1; } return ans; } //Matrix sigma_Matrix(Matrix res,int k){ // 二分求 A + A^2 + A^3 + ... + A^n // if (k == 1) return res; // Matrix B = Power(res,(k+1)/2); // Matrix C = sigma_Matrix(res,k/2); // if (k&1){ // return Add(res,Multiply(Add(res,B),C)); // }else { // return Multiply(Add(Power(res,0),B),C); // } //} ull Power_Int(ull a,int b){ ull res = 1; while(b){ if (b & 1) res = res * a; a = a * a; b >>= 1; } return res; } //ull sigma_Int(ull a,int k){ // 二分 求整数 x + x^2 + x^3 + ... + x^n // if (k==1) return a; // ull b = Power_Int(a,(k+1)/2); // ull c = sigma_Int(a,k/2); // // //printf("b = %llu c = %llu k = %d\n",b,c,k); // if (k & 1){ // return a + (a + b) * c; // }else { // return (1 + b) * c; // } //} // //void print(){ // for (int i=0;i<ac.sz;i++){ // for (int j=0;j<ac.sz;j++) // printf("%llu ",res.mat[i][j]); // puts(""); // } //} void input(){ char s[20]; ac.init(); for (int i=0;i<n;i++){ scanf("%s",s); ac.insert(s); } ac.getfail(); ac.get_Matrix(); // print(); //res = sigma_Matrix(res,l); res = Power(res,l); ull ans = 0; for (int i=0;i<ac.sz+1;i++){ ans += res.mat[0][i]; } ans--; res.r = 2; res.c = 2; res.mat[0][0] = 26; res.mat[0][1] = res.mat[1][1] = 1; res.mat[1][0] = 0; res = Power(res,l); ull sum = res.mat[0][1] + res.mat[0][0]-1; //printf("ans = %llu sum = %llu l = %d\n",ans,sum,l); printf("%llu\n",sum-ans); } //void init(){ // for (int i=0;i<MAX_N;i++) // x.mat[i][i] = 1; //} int main(){ //init(); //freopen("1.txt","r",stdin); while(scanf("%d%d",&n,&l)!=EOF){ input(); } }
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/timelimite/article/details/47359133