UVA11468 Substring

好久不做 (AC) 自动机题了,今天水一道

Description

link

给定一些字符串,然后给出每个字符的概率 (p_i),和一个长度 (L)

我们现在要构造一个长度为 (L) 的字符串,对于这个字符串的每个位置,每个字符有 (p_i) 的概率出现在这个位置

求有多大的概率在这个长度为 (L) 的字符串中不出现任何一个给定的字符串

数据范围? (O() 能过 ())

Solution

先把所有的字符建个自动机,末尾节点打上标记,要与上 (fail) 节点的标记(原因显然)

然后就是个无脑 (dp)

(f_{i,j}) 为当前长度为 (i) 的,匹配到节点 (j) 的概率

暴力转移一下即可

最后(ans=sumlimits_{i=1}^{tot} f_{l,i})

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int N=1010;
	map<char,int> id;
	inline void prework()
	{
		int cnt=0;
		for(int i=0;i<26;++i) id['a'+i]=++cnt;
		for(int i=0;i<26;++i) id['A'+i]=++cnt;
		for(int i=0;i<10;++i) id['0'+i]=++cnt;
		return ; 
	}
	int n,m,ch[N][70],fail[N],tot,cnt,fl[N],l;	
	double p[N],f[110][N];
	char s[N];
	inline void insert()
	{
		int len=strlen(s+1),now=0;
		for(int i=1;i<=len;++i) 
		{
			if(!ch[now][id[s[i]]]) ch[now][id[s[i]]]=++tot;
			now=ch[now][id[s[i]]]; 
		}fl[now]=1;
		return ;
	}
	inline void bfs()
	{
		queue<int> q;
		for(int i=1;i<=62;++i) 
		{
			if(ch[0][i]) q.push(ch[0][i]),fail[ch[0][i]]=0;
		}
		while(!q.empty())
		{
			int fr=q.front(); q.pop();
			for(int i=1;i<=62;++i)
			{
				if(ch[fr][i]) fail[ch[fr][i]]=ch[fail[fr]][i],q.push(ch[fr][i]);
				else ch[fr][i]=ch[fail[fr]][i];
			}fl[fr]|=fl[fail[fr]];
		} 
		return ;
	}
	inline void work()
	{	
		n=read(); 
		memset(ch,0,sizeof(ch)); 
		memset(fail,0,sizeof(fail));
		memset(fl,0,sizeof(fl));
		memset(f,0,sizeof(f)); tot=0;
		memset(p,0,sizeof(p));
		for(int i=1;i<=n;++i) scanf("%s",s+1),insert();
		bfs(); m=read(); f[0][0]=1;
		for(int i=1;i<=m;++i) 
		{
			char s; cin>>s; 
			double tmp; scanf("%lf",&tmp); 
			p[id[s]]+=tmp;
		} l=read(); 
		for(int i=1;i<=l;++i)
		{
			for(int j=0;j<=tot;++j) 
			{
				for(int k=1;k<=62;++k)
				{
					if(!fl[ch[j][k]]) f[i][ch[j][k]]+=f[i-1][j]*p[k];
				}
			}
		}
		double ans=0;
		for(int i=0;i<=tot;++i) ans+=f[l][i];
		printf("Case #%lld: %.6lf
",++cnt,ans);
		return ;
	}
	signed main()
	{
		prework();
		int T=read(); while(T--) work();
		return 0;
	}
}
signed main(){return yspm::main();}

原文地址:https://www.cnblogs.com/yspm/p/13287665.html