【AC自动机】【高斯消元】Magic boy Bi Luo with his excited string problem

【题目描述】
As we know, Bi Luo is a magic boy, he always has some excited questions , now a new question comes.

You are given some excited strings( only including lowercase ),now Bi Luo starts writing letters.Bi Luo will keep writing until one of the given excited strings can match some substrings of his writing string.That’s saying if the goal is reached, Bi Luo will immediately stop his writing.

In each time,Bi Luo will choose one letter among ‘a’ to ‘z’ with equal probability to write.

What’s the excepted length will Bi Luo writing until he reaching the goal?

Hint:

You can esay to caculate the answer of the fitst sample input in following processing:

A n s w e r = l i m n + i = 1 n i ( 25 26 ) i 1 1 26 = 26 Answer=lim_{n→+∞}∑^n_{i=1}i∗(\frac {25}{26})^{i−1}∗\frac{1}{26}=26
【思路】
建出串的AC自动机。定义 d p i dp_i 表示当前在节点i,到结束的期望步数。转移时自然需要枚举所有后继节点。注意到转移可能存在环,由于题目要求精确解,不能使用迭代,所以考虑使用高斯消元。边界条件为:如果点u是一个串的结尾节点,或者点u的fail链到根路径上存在一个点是结尾节点,那么 d p u = 0 dp_u=0
代码:

#include<bits/stdc++.h>
#define re register
#define F(i,a,b) for(int re i=a;i<=b;++i)
#define D(i,a,b) for(int re i=a;i>=b;--i)
#define int long long
using namespace std;
const int N=160+5,mod=1e9+7;
int n,m,a[N][N],b,c;
inline int red(){
    int re data=0;bool w=0; char re ch=getchar();
    while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
    if(ch=='-') w=1,ch=getchar();
    while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return w?-data:data;
}
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int mul(const int&a,const int&b){return 1ll*a*b%mod;}
inline int dec(const int&a,const int&b){return a<b?a-b+mod:a-b;}
inline int ksm(int a,int b){
	int ret=1;
	while(b){
		if(b&1)ret=mul(ret,a);
		b>>=1;a=mul(a,a);
	}return ret;
} 
const int inv=ksm(26,mod-2);
namespace gauss{
	int n,ans[N];
	inline void init(int tot){n=tot;memset(a,0,sizeof(a));}
	inline void solve(int now){
		F(i,now+1,n)while(a[i][now]){
			if(a[i][now]<a[now][now])swap(a[i],a[now]);
			int p=a[i][now]/a[now][now];
			F(j,now,n+1)a[i][j]=dec(a[i][j],mul(p,a[now][j]));
		}
	}
	void work(){
		F(i,0,n)solve(i);
		D(i,n,0){
			D(j,n,i+1)a[i][n+1]=dec(a[i][n+1],mul(ans[j],a[i][j]));
			ans[i]=mul(a[i][n+1],ksm(a[i][i],mod-2));
		}
	}
}
using gauss::ans;
char s[25];
bool vis[N];
int ch[N][26],tot=0,fail[N];
inline void clean(){
	tot=0;
	memset(ch,0,sizeof(ch));
	memset(vis,0,sizeof(vis));
	memset(fail,0,sizeof(fail));
}
inline void add(int len){
	int u=0;
	F(i,1,len){
		int nxt=s[i]-'a';
		u=ch[u][nxt]?ch[u][nxt]:ch[u][nxt]=++tot;
	}vis[u]=1;
}
void bfs(){
	queue<int>q;
	F(i,0,25)if(ch[0][i])q.push(ch[0][i]);
	while(!q.empty()){
		int u=q.front();q.pop();vis[u]|=vis[fail[u]];
		F(i,0,25)if(ch[u][i])fail[ch[u][i]]=ch[fail[u]][i],q.push(ch[u][i]),vis[ch[u][i]]|=vis[u];
			  	 else ch[u][i]=ch[fail[u]][i];
	}gauss::init(tot);
	F(i,0,tot){
		a[i][i]=add(a[i][i],mod-1);
		if(vis[i])continue;
		F(j,0,25)a[i][ch[i][j]]=add(a[i][ch[i][j]],inv);
		a[i][tot+1]=mod-1;
	}gauss::work();
}int T=0;
signed main(){
	int T_T=red();
	while(T_T--){
		clean();n=red();
		F(i,1,n)scanf("%s",s+1),add(strlen(s+1));
		bfs();cout<<"Case #"<<++T<<": "<<ans[0]<<"\n";
	}
}
发布了106 篇原创文章 · 获赞 22 · 访问量 5471

猜你喜欢

转载自blog.csdn.net/weixin_44111457/article/details/103000924