HDU2243
题目描述
长度不超过 L L L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个呢?这里就不考虑单词是否有实际意义。
题解
先考虑直接dp转移,但是考虑到 n n n的大小,显然会T掉。
考虑矩阵乘法,
a
n
s
=
总
方
案
数
−
不
含
词
根
的
单
词
ans=总方案数-不含词根的单词
ans=总方案数−不含词根的单词;
首先前半部分是一个幂和的形式:
A
n
=
2
6
1
+
.
.
.
+
2
6
n
S
n
=
A
n
+
1
=
2
6
0
+
2
6
1
+
.
.
.
+
2
6
n
S
n
+
1
=
26
S
n
+
1
A_n=26^1+...+26^n\\ S_n=A_n+1=26^0+26^1+...+26^n\\ S_{n+1}=26S_n+1
An=261+...+26nSn=An+1=260+261+...+26nSn+1=26Sn+1
显然可以用矩形快速幂解决
后半部分完全相同于POJ2778,就不多赘述。
代码
#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
int tr[50][26],fail[50],val[50],cnt,n,m;
ull sum;
char s[50];
struct Matrix{
ull a[50][50];
Matrix(){memset(a,0,sizeof(a));}
Matrix operator*(const Matrix &b)const{
Matrix res;
for(int i=0;i<=cnt+1;i++)
for(int j=0;j<=cnt+1;j++)
for(int k=0;k<=cnt+1;k++)
res.a[i][j]=(res.a[i][j]+a[i][k]*b.a[k][j]);
return res;
}
}ans,base;
void clear(){
cnt=0;
memset(tr,0,sizeof(tr));
memset(fail,0,sizeof(fail));
memset(val,0,sizeof(val));
}
void init1(){
for(int i=0;i<=49;i++)
for(int j=0;j<=49;j++)
base.a[i][j]=ans.a[i][j]=0;
for(int i=0;i<=cnt;i++){
for(int j=0;j<26;j++){
int x=tr[i][j],y=val[x];
if(!y&&!val[i]) base.a[x][i]++;
}
}for(int i=0;i<=cnt+1;i++) base.a[cnt+1][i]=1;
ans.a[0][0]=1;
}
void init2(){
for(int i=0;i<=49;i++)
for(int j=0;j<=49;j++)
base.a[i][j]=ans.a[i][j]=0;
ans.a[0][0]=ans.a[1][0]=1;
base.a[0][0]=26,base.a[0][1]=base.a[1][1]=1;
}
void ksm(long long b){
while(b){
if(b&1) ans=base*ans;
base=base*base;
b>>=1;
}
}
void DP(){
sum=0;
init1();ksm((long long)m);
for(int i=0;i<=cnt+1;i++) sum+=ans.a[i][0];
init2();ksm((long long)m);
//cout<<sum<<endl;
cout<<ans.a[0][0]-sum<<endl;
}
void build(){
int u=0,len=strlen(s+1);
for(int i=1;i<=len;i++){
int c=s[i]-'a';
if(!tr[u][c]) tr[u][c]=++cnt;
u=tr[u][c];
}val[u]=1;
}
void getfail(){
queue<int>q;
for(int i=0;i<26;i++)
if(tr[0][i]) q.push(tr[0][i]);
while(q.size()){
int u=q.front();q.pop();
for(int i=0;i<26;i++){
if(!tr[u][i]) tr[u][i]=tr[fail[u]][i];
else{
int x=tr[u][i],y=fail[u];
while(y&&!tr[y][i]) y=fail[y];
fail[x]=tr[y][i],val[x]|=val[fail[x]];
}
}
}
}
signed main(){
while(~scanf("%d%d",&n,&m)){
clear();
for(int i=1;i<=n;i++)
scanf("%s",s+1),build();
getfail();DP();
}return 0;
}