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

题目大意:给定n个长度为l的模式串,现在要用前m个大写字母生成一个随机串,每个字符有自己的出现几率,第一次出现的字符串获胜,求最终每个字符串的获胜几率

建出AC自动机,搞出转移矩阵

如果某个节点是模式串那么这个节点只向自己连一条概率为1的出边

然后把转移矩阵自乘50遍即可

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 120
using namespace std;
int n,l,m,limit;
int pos[M];
char s[M];
double possibility[M];
namespace Aho_Corasick_Automaton{
	struct Trie{
		Trie *son[10],*fail;
		int ed;
	}*root,mempool[M],*C=mempool;
	void Insert(Trie *&p,char *s,int pos)
	{
		if(!p) p=++C;
		if(!*s)
		{
			p->ed=pos;
			::pos[pos]=p-mempool;
			return;
		}
		Insert(p->son[*s-'A'],s+1,pos);
	}
	void Build_Tree()
	{
		static Trie *q[M];
		int i,r=0,h=0;
		for(i=0;i<m;i++)
			if(root->son[i])
				(q[++r]=root->son[i])->fail=root;
			else
				root->son[i]=root;
		while(r!=h)
		{
			Trie *p=q[++h];
			for(i=0;i<m;i++)
				if(p->son[i])
					(q[++r]=p->son[i])->fail=p->fail->son[i];
				else
					p->son[i]=p->fail->son[i];
		}
	}
}
class Matrix{
private:
	double xx[M][M];
public:
	Matrix()
	{
		memset(xx,0,sizeof xx);
	}
	Matrix(bool)
	{
		int i;
		memset(xx,0,sizeof xx);
		for(i=0;i<=limit;i++)
			xx[i][i]=1;
	}
	double* operator [] (int x)
	{
		return xx[x];
	}
	friend void operator *= (Matrix &x,Matrix y)
	{
		int i,j,k;
		Matrix z;
		for(i=1;i<=limit;i++)
			for(j=1;j<=limit;j++)
				for(k=1;k<=limit;k++)
					z[i][j]+=x[i][k]*y[k][j];
		x=z;
	}
}f;
int main()
{
	using namespace Aho_Corasick_Automaton;
	int i,x,p,q;
	cin>>n>>l>>m;
	for(i=0;i<m;i++)
	{
		scanf("%d%d",&p,&q);
		possibility[i]=(double)p/q;
	}
	for(i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		Insert(root,s+1,i);
	}
	Build_Tree();
	limit=C-mempool;
	for(i=1;i<=limit;i++)
	{
		if(mempool[i].ed)
			f[i][i]=1;
		else
			for(x=0;x<m;x++)
				f[i][mempool[i].son[x]-mempool]+=possibility[x];
	}
	for(i=1;i<=50;i++)
		f*=f;
	for(i=1;i<=n;i++)
		printf("%.2lf\n",f[1][pos[i]]);
	return 0;
}
时间: 2024-10-08 14:25:30

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

【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 <

●BZOJ 1444 [Jsoi2009]有趣的游戏

题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1444题解.1: 概率dp,矩阵乘法,快速幂. 对所有串建立AC自动机, 那么如果在trie树的节点上转移到一个打了标记的节点,就意味着该标记对应的人取得胜利. (由于题中明确说明串长相同,串又互不相同,所以即表明着建立AC自动机后整个trie树中只有n个打了标记的节点,同时不会存在某些节点无法转移的问题.) 然后建立trie.size×trie.size大小的转移矩阵trans,每个位置t

[BZOJ 1009] [HNOI2008] GT考试 【AC自动机 + 矩阵乘法优化DP】

题目链接:BZOJ - 1009 题目分析 题目要求求出不包含给定字符串的长度为 n 的字符串的数量. 既然这样,应该就是 KMP + DP ,用 f[i][j] 表示长度为 i ,匹配到模式串第 j 位的字符串个数,然后转移就是可以从第 j 位加上一个字符转移到另一个位置. 然而..我并没有写过KMP + DP,我觉得还是写AC自动机+DP比较简单..于是,尽管只有一个模式串,我还是写了AC自动机+DP. 然后就是建出AC自动机,f[i][j] 表示长度为 i ,走到节点 j 的字符串的个数.

BZOJ 1009 [HNOI2008]GT考试 AC自动机+矩阵乘法

题意:链接略 方法: AC自动机+矩阵乘法 解析: 和POJ 2778 一样的题. 大概的思路就是我们建AC自动机的时候需要注意如果某个点是一个串的结尾的话,那么下面的节点都要看成结尾节点. 然后按照AC自动机赋一下矩阵内部值就好了. 赋的矩阵代表从一个节点走一步走到另一个节点有多少方案. 然后经典模型,矩阵的n次方即可. 代码: #include <queue> #include <cstdio> #include <cstring> #include <ios

poj2778DNA Sequence(AC自动机+矩阵乘法)

链接 看此题前先看一下matrix67大神写的关于十个矩阵的题目中的一个,如下: 经典题目8 给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值    把给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j.令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就等于从点i到点j恰好经过2条边的路径数(枚举k为中转点).类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数.同理,如果要求经过k步的路径数,我们只需要二分求出A^k

BZOJ 2553 BeiJing2011 禁忌 AC自动机+矩阵乘法

题目大意:给定n个模式串,定义一个字符串的伤害为所有子串的划分中最多包含的模式串数量,求长度为len的字符串的伤害期望值 小五prpr,恋恋prpr,大小姐prpr 首先建立AC自动机 令f[i][j]表示长度为i的字符串在AC自动机上的第j个节点的伤害期望值 如果要走到某个节点是危险节点或者fail指针指向危险节点,就ans++,然后回到根节点 这样构造出来的矩阵做快速幂= = 这么做都会把- - 不会别骂我- - 但是跑完发现找不到答案- - 因此我们需要稍微改造一下- - 新建一个节点 如

POJ 2778 DNA Sequence (AC自动机,矩阵乘法)

题意:给定n个不能出现的模式串,给定一个长度m,要求长度为m的合法串有多少种. 思路:用AC自动机,利用AC自动机上的节点做矩阵乘法. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<string> 6 #include<algorithm> 7 #include<queue> 8 #defin

【BZOJ1009】【HNOI2008】GT考试 AC自动机+矩阵乘法

广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44003109"); } 题解: 建立AC自动机的过程可以改为KMP. 反正单串233. 代码: #include <queue> #include <cstdio> #include <cstring&

DNA Sequence POJ - 2778 AC 自动机 矩阵乘法

定义重载运算的时候一定要将矩阵初始化,因为这个调了一上午...... Code: #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<string> #define maxn 100000 typedef long long ll; using namespace std; void setIO(string a){ freopen((a+