<span>HDU-2243 考研路茫茫——单词情结 AC自动机+矩阵快速幂</span>
题意
给n个模式串,问有多少个长度不超过L的字符串中至少出现一种模式串。
分析
有多少个长度为L的字符串中不出现任意一个模式串的题已经做过,构造一个矩阵\(A\),答案\(s_n\)即为\(s_0*A^n\)
用矩阵快速幂算下就行了,这题的计算方法就显然是\(26^0+26^1+26^2+\dots+26^n-(s_0*A^0+s_0*A^1+s_0*A^2+\dots+s_0*A^n)\)
这样显然会超时,考虑重新构造两个矩阵
\[\left [ \begin{matrix}26^n&s_n\end{matrix}\right ] \times \left [ \begin{matrix}26&1\\0&1\end{matrix}\right ] =\left [ \begin{matrix}26^{n+1}&s_{n+1}\end{matrix}\right ] \]
设字典树一共\(m\)个结点,我们要构造一个\((m+1)\times(m+1)\)的矩阵
\[\left [ \begin{matrix}f[n][0]&\dots&f[n][m-1]&s_n\end{matrix}\right ] \times \left [ \begin{matrix}A&1\\0&1\end{matrix}\right ] =\left [ \begin{matrix}f[n+1][0]&\dots&f[n+1][m-1]&s_{n+1}\end{matrix}\right ] \]
对于取模,直接用ull自然溢出就行了。
Code
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
#define ll unsigned long long
using namespace std;
const int inf=1e9;
const ll mod=1e9+7;
const int maxn=1e5+10;
int n;
ll L;
char s[11];
struct mat{
int n;
ll a[40][40];
mat(){
memset(a,0,sizeof(a));
}
mat(int _n){
n=_n;memset(a,0,sizeof(a));
}
mat operator *(const mat &r)const{
mat ret=mat(n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
ret.a[i][j]+=a[i][k]*r.a[k][j];
return ret;
}
};
mat A,B=mat(2);
mat ksm(mat a,ll b){
mat ret=mat(a.n);
for(int i=0;i<ret.n;i++) ret.a[i][i]=1;
while(b){
if(b&1) ret=ret*a;
b>>=1;
a=a*a;
}
return ret;
}
struct ACtree{
int son[maxn][26],fail[maxn],ed[maxn],tot;
int newnode(){
for(int i=0;i<26;i++) son[tot][i]=0;
ed[tot++]=0;
return tot-1;
}
void init(){
tot=0;newnode();
}
void ins(char s[]){
int rt=0,m=strlen(s);
for(int i=0;i<m;i++){
if(!son[rt][s[i]-'a']) son[rt][s[i]-'a']=newnode();
rt=son[rt][s[i]-'a'];
}
ed[rt]=1;
}
void gao(){
queue<int>q;
for(int i=0;i<26;i++) if(son[0][i]) fail[son[0][i]]=0,q.push(son[0][i]);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<26;i++){
if(son[u][i]){
fail[son[u][i]]=son[fail[u]][i];
q.push(son[u][i]);
}else{
son[u][i]=son[fail[u]][i];
}
ed[son[u][i]]|=ed[fail[son[u][i]]];
}
}
A=mat(tot+1);
for(int i=0;i<tot;i++){
for(int j=0;j<26;j++){
if(ed[son[i][j]]) continue;
A.a[i][son[i][j]]++;
}
}
for(int i=0;i<=tot;i++) A.a[i][tot]=1;
}
ll qy(){
ll ans=0;
mat ret=ksm(B,L);
ans+=ret.a[0][1]+ret.a[0][0];
ret=ksm(A,L);
for(int i=0;i<=tot;i++) ans-=ret.a[0][i];
return ans;
}
}AC;
int main(){
//ios::sync_with_stdio(false);
//freopen("in","r",stdin);
B.a[0][0]=26,B.a[0][1]=B.a[1][1]=1;
while(~scanf("%d%llu",&n,&L)){
AC.init();
for(int i=1;i<=n;i++){
scanf("%s",s);
AC.ins(s);
}
AC.gao();
printf("%llu\n",AC.qy());
}
return 0;
}