标签:
题目链接: 考研路茫茫――单词情结
做本题前,个人建议先做一下POJ 2778
http://blog.csdn.net/u013446688/article/details/47378255
POJ2778 是求长度为n,不包含模式串的字符串个数。
而本题是求长度为n,包含模式串的字符串个数。直接用字符串总数减去不包含模式串的字符串个数即为所求。
同样是AC自动机 + 矩阵快速幂。但是还是有所不同的。
因为对2^64取模,所以定义数据类型为unsigned long long就可以了,这样就实现了自动取模。
本题使用AC自动机类似得到状态转移的矩阵。
根据矩阵的性质
|A , 1| |A^n , 1+A^1+A^2+....+A^(n-1)|
|0 , 1| 的n次方等 | 0 , 1 |
但是因为要求和。
所以在POJ 2778 得到的L*L的矩阵中,需要增加一维,第L+1列全部为1。
字符串总数是26^1 + 26^2 + ......+ 26^m。
f[n]=1 + 26^1 + 26^2 +...26^n
f[n]=26*f[n-1]+1
{f[n] 1} = {f[n-1] 1}[26 0;1 1]
数是f[L]-1;
此题的L<2^31.矩阵的幂不能是L+1次,否则就超时了
AC代码:
#include <iostream> #include <cstdio> #include <queue> #include <cstring> #include <algorithm> using namespace std; typedef unsigned long long ULL; struct Matrix{ ULL mat[40][40]; int n; Matrix(){} Matrix(int _n){ n = _n; for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) mat[i][j] = 0; } Matrix operator *(const Matrix &b) const{ Matrix ret = Matrix(n); for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) for(int k = 0; k < n; k++) ret.mat[i][j] += mat[i][k] * b.mat[k][j]; return ret; } }; Matrix pow_Mat(Matrix a, int n){ Matrix ret = Matrix(a.n); for(int i = 0; i < ret.n; i ++) ret.mat[i][i] = 1; Matrix tmp = a; while(n){ if(n & 1) ret = ret * tmp; tmp = tmp * tmp; n >>= 1; } return ret; } struct Trie{ int next[40][26], fail[40]; bool end[40]; int root, L; int newnode(){ for(int i = 0; i < 26; i++) next[L][i] = -1; end[L++] = false; return L-1; } void init(){ L = 0; root = newnode(); } void insert(char s[]){ int len = strlen(s); int now = root; for(int i = 0; i < len; i++){ if(next[now][s[i] - 'a'] == -1) next[now][s[i] - 'a'] = newnode(); now = next[now][s[i] - 'a']; } end[now] = true; } void build(){ queue<int> Q; for(int i = 0; i < 26; i ++){ if(next[root][i] == -1) next[root][i] = root; else{ fail[ next[root][i] ] = root; Q.push(next[root][i]); } } while(!Q.empty()){ int now = Q.front(); Q.pop(); if(end[ fail[now] ] == true) end[now] = true; for(int i = 0; i < 26; i ++){ if(next[now][i] == -1) next[now][i] = next[ fail[now] ][i]; else{ fail[ next[now][i] ] = next[ fail[now] ][i]; Q.push(next[now][i]); } } } } Matrix getMatrix(){ Matrix ret = Matrix(L+1); for(int i = 0; i < L; i ++) for(int j = 0; j < 26; j ++) if(end[ next[i][j] ] == false) ret.mat[i][ next[i][j] ] ++; for(int i = 0; i < L+1; i++) ret.mat[i][L] = 1; return ret; } }; Trie ac; char buf[10]; int main(){ #ifdef sxk freopen("in.txt", "r", stdin); #endif //sxk int n, L; while(scanf("%d%d", &n, &L) == 2){ ac.init(); for(int i = 0; i < n; i ++){ scanf("%s", buf); ac.insert(buf); } ac.build(); Matrix a = ac.getMatrix(); a = pow_Mat(a, L); ULL res = 0; //不含模式串的字符串个数 for(int i = 0; i < a.n; i ++) res += a.mat[0][i]; res --; a = Matrix(2); a.mat[0][0] = 26; a.mat[1][0] = a.mat[1][1] = 1; a = pow_Mat(a, L); ULL ans = a.mat[1][0] + a.mat[0][0]; //字符串总个数 ans --; cout<<ans - res<<endl; } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU 2243 考研路茫茫――单词情结 (AC自动机 + 矩阵快速幂)
标签:
原文地址:http://blog.csdn.net/u013446688/article/details/47399049