【BZOJ1444】[Jsoi2009]有趣的游戏 AC自动机+概率DP+矩阵乘法

【BZOJ1444】[Jsoi2009]有趣的游戏

Description

Input

注意 是0<=P

Output

Sample Input


Sample Output


HINT

 30%的数据保证, n ≤ 2. 50%的数据保证, n ≤ 5. 100%的数据保证, n , l, m≤ 10.

题解:本题的做法真的很多啊,概率DP,期望DP,当然还有矩乘黑科技~

就是先跑AC自动机,弄出转移矩阵,然后自乘50次就行了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
int n,l,m,tot;
double c[30],ans[20];
queue<int> q;
struct node
{
	int ch[30],fail,dan;
}p[110];
char str[20];
struct M
{
	double v[110][110];
	M (){memset(v,0,sizeof(v));}
	double* operator [](int x)	{return v[x];}
	M operator * (M a) const
	{
		M c;
		for(int i=1;i<=tot;i++)	for(int j=1;j<=tot;j++)	for(int k=1;k<=tot;k++)	c[i][j]+=v[i][k]*a[k][j];
		return c;
	}
};
M x;
void build()
{
	int i,u;
	q.push(1);
	while(!q.empty())
	{
		u=q.front(),q.pop();
		for(i=0;i<m;i++)
		{
			if(!p[u].ch[i])
			{
				if(u==1)	p[u].ch[i]=1;
				else	p[u].ch[i]=p[p[u].fail].ch[i];
				continue;
			}
			q.push(p[u].ch[i]);
			if(u==1)
			{
				p[p[u].ch[i]].fail=1;
				continue;
			}
			p[p[u].ch[i]].fail=p[p[u].fail].ch[i];
		}
	}
}
int main()
{
	scanf("%d%d%d",&n,&l,&m);
	int i,j,u;
	double a,b;
	for(i=0;i<m;i++)	scanf("%lf%lf",&a,&b),c[i]=a/b;
	for(tot=i=1;i<=n;i++)
	{
		scanf("%s",str),u=1;
		for(j=0;j<l;j++)
		{
			if(!p[u].ch[str[j]-'A'])	p[u].ch[str[j]-'A']=++tot;
			u=p[u].ch[str[j]-'A'];
		}
		p[u].dan=i;
	}
	build();
	for(i=1;i<=tot;i++)
	{
		if(p[i].dan) x[i][i]=1;
		else	for(j=0;j<m;j++)	x[i][p[i].ch[j]]+=c[j];
	}
	for(i=1;i<=50;i++)	x=x*x;
	for(i=1;i<=tot;i++)	if(p[i].dan)	ans[p[i].dan]=x[1][i];
	for(i=1;i<=n;i++)	printf("%.2lf\n",ans[i]);
	return 0;
}
/*
1 10 10
1 10
1 10
1 10
1 10
1 10
1 10
1 10
1 10
1 10
1 10
AAAAAAAAAA
 */
posted @ 2017-06-20 16:21  CQzhangyu  阅读(337)  评论(0编辑  收藏  举报