【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
 */
时间: 2024-10-10 15:35:08

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

BZOJ 1444 JSOI2009 有趣的游戏 AC自动机+矩阵乘法

题目大意:给定n个长度为l的模式串,现在要用前m个大写字母生成一个随机串,每个字符有自己的出现几率,第一次出现的字符串获胜,求最终每个字符串的获胜几率 建出AC自动机,搞出转移矩阵 如果某个节点是模式串那么这个节点只向自己连一条概率为1的出边 然后把转移矩阵自乘50遍即可 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 120 us

【BZOJ2553】[BeiJing2011]禁忌 AC自动机+期望DP+矩阵乘法

[BZOJ2553][BeiJing2011]禁忌 Description Magic Land上的人们总是提起那个传说:他们的祖先John在那个东方岛屿帮助Koishi与其姐姐Satori最终战平.而后,Koishi恢复了读心的能力…… 如今,在John已经成为传说的时代,再次造访那座岛屿的人们却发现Koishi遇到了新麻烦. 这次她遇到了Flandre Scarlet——她拥有可以使用禁忌魔法而不会受到伤害的能力. 为了说明什么是禁忌魔法及其伤害,引入以下概念: 1.字母集A上的每个非空字符

【BZOJ4820】[Sdoi2017]硬币游戏 AC自动机+概率DP+高斯消元

[BZOJ4820][Sdoi2017]硬币游戏 Description 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利.大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实在是太单调了.同学们觉得要加强趣味性,所以要找一个同学扔很多很多次硬币,其他同学记录下正反面情况.用H表示正面朝上,用T表示反面朝上,扔很多次硬币后,会得到一个硬币序列.比如HTT表示第一次正面朝上,后两次反面朝上.但扔到什么时候停止呢?大家提议,选出n个同学,每个同学猜一个长度为m的序列,当某

[AC自动机+概率dp] hdu 3689 Infinite monkey theorem

题意: 给n个字母,和m次数. 然后输入n个字母出现的概率 然后再给一个目标串str 然后问m次中敲出目标串的概率是多少. 思路: AC自动机+概率dp的简单题. 首先建立trie图,然后就是状态转移了 dp版本: dp三重循环变量次数,节点数,和字母数 代码: #include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"

bzoj1444 有趣的游戏(AC自动机+概率dp)

题意: 给定n个长度为l的模式串,现在要用前m个大写字母生成一个随机串,每个字符有自己的出现几率,第一次出现的字符串获胜,求最终每个字符串的获胜几率. 分析: 容易想到先把所有的字符串建成一个AC自动机 然后对于生成的随机串就相当于从AC自动机的root开始在自动机上走,然后求走到每个单词节点的概率 因为这是存在环的,不是DAG图,所以不能直接DP 考虑构造出刚开始的转移矩阵,然后对转移矩阵作矩阵乘法不断迭代就能得到正确答案了 转移矩阵如何建呢? 1)a[i][ch[i][j]]+=p[j] (

BZOJ1444 : [Jsoi2009]有趣的游戏

建立AC自动机,并求出转移矩阵. 再用$\sum E(终止节点)=1$去替换第一个方程,高斯消元即可. 时间复杂度$O(n^3l^3)$. 注意精度问题,要特判0.00的情况. #include<cstdio> #include<cmath> #include<algorithm> #define N 110 using namespace std; int n,l,S,i,j,k,tot,son[N][10],v[N],fail[N],q[N],fin[N]; cha

UVa 11468 Substring (AC自动机+概率DP)

题意:给出一个字母表以及每个字母出现的概率.再给出一些模板串S.从字母表中每次随机拿出一个字母,一共拿L次组成一个产度为L的串, 问这个串不包含S中任何一个串的概率为多少? 析:先构造一个AC自动机,然后随机生成L个字母,就是在AC自动机的某个结点走多少步,dp[i][j] 表示在 i 结点,并且剩下 j 步, 然后记忆化搜索就OK了. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <

UVa 11468 (AC自动机 概率DP) Substring

将K个模板串构成一个AC自动机,那些能匹配到的单词节点都称之为禁止节点. 然后问题就变成了在Tire树上走L步且不经过禁止节点的概率. 根据全概率公式用记忆化搜索求解. 1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 using namespace std; 5 6 const int maxnode = 500; 7 const int sigma_size = 64; 8 int idx[2

【AC自动机】【矩阵乘法】poj2778 DNA Sequence

http://blog.csdn.net/morgan_xww/article/details/7834801 讲得很好~可以理解自动机的本质,就是一个用来状态转移的东西~对于确定的输入而言,可以从初始状态,按照转移边,转移到确定的终止状态. 而这种转移可以用矩乘加速. #include<cstdio> #include<cstring> #include<vector> #include<queue> #include<iostream> us