【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 Answer=limn+i=1ni(2625)i1261=26
【思路】
建出串的AC自动机。定义 d p i dp_i dpi表示当前在节点i,到结束的期望步数。转移时自然需要枚举所有后继节点。注意到转移可能存在环,由于题目要求精确解,不能使用迭代,所以考虑使用高斯消元。边界条件为:如果点u是一个串的结尾节点,或者点u的fail链到根路径上存在一个点是结尾节点,那么 d p u = 0 dp_u=0 dpu=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";
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值