首先利用补集转化思想,将问题转化为求一个词根都不包含的单词有多少种。
可以想到将所有的词根建为AC自动机,然后使用DP求解。
由于长度范围很大,可以使用矩阵乘法加速。
并且题目中要求的是“长度不超过L的”,所以要求sum = A ^ 1 + A ^ 2 + A ^ 3 + ...... + A ^ L
所有情况tot = 26 ^ 1 + 26 ^ 2 + 26 ^ 3 + ..... + 26 ^ L
最后ans = tot - sum
代码:
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 30;
const int child_num = 26;
int matcal[maxn];
int sz,matnum;
long long n,k;
struct Matrix
{
unsigned long long v[maxn][maxn];
int x,y;
Matrix()
{
memset(v,0,sizeof(v));
x = y = 0;
}
}mat;
class ACAutumaton
{
public:
int chd[maxn][child_num];
int fail[maxn],val[maxn];
int Q[maxn],ID[128];
int cnt;
void Reset()
{
memset(chd[0],0,sizeof(chd[0]));
memset(fail,0,sizeof(fail));
for(int i = 0;i < 26;i++)ID['a'+i] = i;
sz = 1;
}
void Insert(char *a,int key)
{
int p = 0;
for(;*a; a++)
{
int c = ID[*a];
if(!chd[p][c])
{
memset(chd[sz],0,sizeof(chd[sz]));
val[sz] = 0;
chd[p][c] = sz++;
}
p = chd[p][c];
}
val[p] = key;
}
void Construct()
{
int *s = Q,*e = Q;
for(int i = 0;i < child_num;i++)
{
if(chd[0][i])
{
fail[ chd[0][i] ] = 0;
*e ++ = chd[0][i];
}
}
while(s != e)
{
int u = *s++;
for(int i = 0;i < child_num;i++)
{
int &v = chd[u][i];
if(v)
{
*e ++ = v;
fail[v] = chd[ fail[u] ][i];
val[v] |= val[fail[v]];
}
else v = chd[ fail[u] ][i];
}
}
}
}AC;
void init()
{
freopen("hdu2243.in","r",stdin);
freopen("hdu2243.out","w",stdout);
}
void work()
{
memset(mat.v,0,sizeof(mat.v));
memset(matcal,0,sizeof(matcal));
matnum = 0;
for(int i = 0;i < sz;i++)
if(!AC.val[i])matcal[i] = ++matnum;
mat.x = matnum;mat.y = matnum;
for(int i = 0;i < sz;i++)
{
if(!AC.val[i])
{
for(int j = 0;j < child_num;j++)
{
if(!AC.val[AC.chd[i][j]])
mat.v[matcal[i]][matcal[AC.chd[i][j]]]++;
}
}
}
}
Matrix mtAdd(Matrix A,Matrix B)
{
Matrix C;
C.x = A.x;C.y = B.y;
for(int i = 1;i <= A.x;i++)
{
for(int j = 1;j <= B.y;j++)
{
C.v[i][j] = A.v[i][j] + B.v[i][j];
}
}
return C;
}
Matrix mtMul(Matrix A,Matrix B)
{
if(!A.x || !A.y)return B;
Matrix C;
C.x = A.x;C.y = B.y;
for(int i = 1;i <= A.x;i++)
{
for(int j = 1;j <= B.y;j++)
{
for(int k = 1;k <= A.y;k++)
{
C.v[i][j] += A.v[i][k] * B.v[k][j];
}
}
}
return C;
}
Matrix mtPow(Matrix A,long long b)
{
Matrix tmp = A,ret;
while(b)
{
if(b & 1)ret = mtMul(ret,tmp);
tmp = mtMul(tmp,tmp);
b >>= 1;
}
return ret;
}
Matrix mtCal(Matrix A,long long b)
{
if(b == 1)return A;
Matrix B = mtPow(A,(b + 1) / 2);
Matrix C = mtCal(A,b / 2);
if(b % 2 == 0)return mtAdd(mtMul(B,C),C);
else return mtAdd(mtAdd(B,mtMul(C,B)),C);
}
unsigned long long quick_pow(long long a,long long b)
{
unsigned long long tmp = a,ret = 1;
while(b)
{
if(b & 1)ret = ret * tmp;
tmp = tmp * tmp;
b >>= 1;
}
return ret;
}
unsigned long long calc(int p,long long b)
{
if(b == 1)return p;
unsigned long long tmp1 = quick_pow(p,(b + 1) / 2);
unsigned long long tmp2 = calc(p,b / 2);
if(b % 2 == 0)return (tmp1 * tmp2) + tmp2;
else return tmp1 + tmp2 + tmp1 * tmp2;
}
void solve()
{
AC.Construct();
work();
Matrix tmp = mtCal(mat,k);
unsigned long long tot = calc(26,k),ans = 0;
for(int i = 1;i <= matnum;i++)
{
ans += tmp.v[1][i];
}
printf("%llu\n",tot - ans);
}
void readdata()
{
while(scanf("%lld%lld",&n,&k) != EOF)
{
AC.Reset();
char s[10];
for(int i = 1;i <= n;i++)
{
scanf("%s",s);
AC.Insert(s,1);
}
solve();
}
}
int main()
{
init();
readdata();
return 0;
}