题目大意:
就是现在给出一些单词的词根,问长度不超过L ( 1 <= L < 2^31) 的只含小写英文字母的串中至少包含一个词根的串有多少个,输出结果对2^64取模输出
大致思路:
这道题和POJ 2778很像(题解戳这里),但是这题需要求得是含有词根的串的数量,很容易想到先求出不包含的个数,然后用全部的减去它即可,这个地方由于是长度不超过L,那么相对于POJ 2778来说需要求矩阵 A的 1~L次方的第一行的和,这里我用的是二分递归来求得等比矩阵和,但是容易RuntimeError(Stack_Overflow)后来减小了矩阵类的数组就过了
这里应该有更优的解法, 不过我还是就用了递归求矩阵的和过了
另外算26 + 26^2 + ... +26^L的时候也是构造的矩阵算的..
对于2^64取模可以利用unsigned long long 的溢出来解决,也就没什么好说的
代码如下:
Result : Accepted Memory : 1696 KB Time : 421 ms
/*
* Author: Gatevin
* Created Time: 2014/11/19 17:42:08
* File Name: Kagome.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
int n, L, bound;
struct Matrix
{
unsigned long long a[26][26];
Matrix()
{
for(int i = 0; i < 26; i++)
for(int j = 0; j < 26; j++)
a[i][j] = i == j ? 1 : 0;
return;
}
unsigned long long* operator[](int i)
{
return a[i];
}
};
Matrix operator * (Matrix m1, Matrix m2)
{
Matrix rm;
for(int i = 0; i < bound; i++)
for(int j = 0; j < bound; j++)
{
rm[i][j] = 0;
for(int k = 0; k < bound; k++)
{
rm[i][j] += m1[i][k]*m2[k][j];
}
}
return rm;
}
Matrix operator + (Matrix m1, Matrix m2)
{
Matrix rm;
for(int i = 0; i < bound; i++)
for(int j = 0; j < bound; j++)
rm[i][j] = m1[i][j] + m2[i][j];
return rm;
}
Matrix quick(Matrix base, int pow)//快速幂
{
Matrix I;
while(pow)
{
if(pow & 1)
I = I * base;
base = base * base;
pow >>= 1;
}
return I;
}
/*
* 这个地方像我这么做容易爆栈,刚开始交的时候爆栈了好几次
* 应该有更好的方法来代替
*/
Matrix Geo(Matrix base, int pow)//矩阵二分求和base + base^2 + base^3 + ... + base^pow
{
if(pow == 1) return base;
Matrix I;
if(pow & 1) return Geo(base, (pow - 1) >> 1) * ( I + quick(base, (pow - 1) >> 1)) + quick(base, pow);
return Geo(base, pow >> 1)*( I + quick(base, pow >> 1));
}
struct Trie
{
int next[6*6][26], fail[6*6];
bool end[6*6], vis[6*6];
int L, root;
int newnode()
{
for(int i = 0; i < 26; i++)
next[L][i] = -1;
end[L++] = 0;
return L - 1;
}
void init()
{
L = 0;
root = newnode();
return;
}
void insert(char *s)
{
int now = root;
for(; *s; s++)
{
if(next[now][*s - 'a'] == -1)
next[now][*s - 'a'] = newnode();
now = next[now][*s - 'a'];
}
end[now] = 1;
return;
}
void build()//建立状态转移图
{
fail[root] = root;
queue <int> Q;
Q.push(root);
while(!Q.empty())
{
int now = Q.front();
Q.pop();
if(end[fail[now]]) end[now] = 1;
for(int i = 0; i < 26; i++)
if(next[now][i] == -1)
next[now][i] = now == root ? root : next[fail[now]][i];
else
{
fail[next[now][i]] = now == root ? root : next[fail[now]][i];
Q.push(next[now][i]);
}
}
return;
}
Matrix matrix()//BFS计算矩阵
{
unsigned long long m[26][26];
memset(m, 0, sizeof(m));
memset(vis, 0, sizeof(vis));
queue <int> Q;
Q.push(root);
vis[root] = 1;
while(!Q.empty())
{
int now = Q.front();
Q.pop();
for(int i = 0; i < 26; i++)
if(!end[next[now][i]])
{
m[now][next[now][i]]++;
if(!vis[next[now][i]])
{
Q.push(next[now][i]);
vis[next[now][i]] = 1;
}
}
}
Matrix R;
vector <int> v;
for(int i = 0; i < L; i++)
if(vis[i]) v.push_back(i);
for(unsigned int i = 0; i < v.size(); i++)
for(unsigned int j = 0; j < v.size(); j++)
R[i][j] = m[v[i]][v[j]];
bound = v.size();
return R;
}
};
Trie AC;
int main()
{
char ts[8];
while(~scanf("%d %d", &n, &L))
{
AC.init();
while(n--)
{
scanf("%s", ts);
AC.insert(ts);
}
AC.build();
Matrix A = AC.matrix();
Matrix F = Geo(A, L);
unsigned long long ans1 = 0;
for(int i = 0; i < bound; i++)
ans1 += F[0][i];
Matrix N;
N[0][0] = 1; N[0][1] = 1;
N[1][0] = 0; N[1][1] = 26;
bound = 2;
Matrix ALL = quick(N, L);//矩阵快速幂求等比数列26 + 26^2 + ... + 26^n的值
unsigned long long ans2 = ALL[0][1] + ALL[1][1] - 1;
unsigned long long ans = ans2 - ans1;
printf("%I64u\n", ans);
}
return 0;
}