题目链接: 考研路茫茫――单词情结
做本题前,个人建议先做一下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;
}