HDU-2243 考研路茫茫——单词情结 AC自动机+矩阵快速幂

题意

给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 [ egin{matrix}26^n&s_nend{matrix} ight ] imes left [ egin{matrix}26&1\0&1end{matrix} ight ] =left [ egin{matrix}26^{n+1}&s_{n+1}end{matrix} ight ] ]

设字典树一共(m)个结点,我们要构造一个((m+1) imes(m+1))的矩阵

[left [ egin{matrix}f[n][0]&dots&f[n][m-1]&s_nend{matrix} ight ] imes left [ egin{matrix}A&1\0&1end{matrix} ight ] =left [ egin{matrix}f[n+1][0]&dots&f[n+1][m-1]&s_{n+1}end{matrix} ight ] ]

对于取模,直接用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
",AC.qy());
	}
	return 0;
}
原文地址:https://www.cnblogs.com/xyq0220/p/11593462.html