<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;
}
全部评论

相关推荐

我见java多妩媚:大外包
点赞 评论 收藏
分享
10-17 12:16
同济大学 Java
7182oat:快快放弃了然后发给我,然后让我也泡他七天最后再拒掉,狠狠羞辱他一把😋
点赞 评论 收藏
分享
11-28 17:58
门头沟学院 Java
美团 JAVA开发 n×15.5
牛客786276759号:百度现在晋升很难的 而且云这块的业务没美团好 你看百度股价都跌成啥样了
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务