题面

题目描述

小阳阳发明了一个有趣的游戏:有n个玩家,每一个玩家均有一个长度为 l 的字母序列,任何两个玩家的字母序列不同。共有m种不同的字母,所有的字母序列都由这m种字母构成,为了方便,我们取大写字母的前。个字母。例如。m =3 , l = 4 , ABAA , CBCA 为两个合法的字母序列。现在由小阳阳来操控一台神奇的机器,每个时刻机器会随机产生一个字母,其中第i种字母随机出来的概率为pi/qi,显然 sum(pi/qi)=1 。这样T个时刻后机器会产生一个长度为 T 的字母序列。如果某个时刻某个玩家发现自己的字母序列在机器产生的字母序列中出现了,“出现”的定义是玩家的字母序列是机器产生的字母序列中连续的一段,那么我们称这个玩家获胜,游戏结束。现在小阳阳感兴趣的一个问题是,每个玩家分别有多大的概率能获得这场游戏的胜利呢?

输入格式

第一行有三个正整数n,l,m表示有n个人,每个人的字母序列长度为l,共有m个字母。

接下来m行,每行有两个非负整数p,q,表示随机到第i个字母的概率为p/q(0<=p<=q<=10,(p,q)=1)。数据保证m个字母的随机概率之和为1。

接下来n行,每行有一个长度为l的字母序列,表示第i个人的字母序列。数据保证所有的字母为大写字母的前m个且没有两个字母序列完全相同。

输出格式

包含n行,每行包含一个实数,表示第i个人获胜的概率,输出结果四舍五入到两位小数。

样例输入1

3 2 2
1 2
1 2
AB
BA
AA

样例输出1

0.25
0.50
0.25

样例输入2

3 4 2
1 2
1 2
AABA
ABAA
BAAA

样例输出2

0.31
0.33
0.37

样例说明1

两种字母 A 和 B ,概率均为 1/2。若前两个字母为 AB , BA 或AA,均有一个人获胜,获胜概率为 1 / 4 ;若前两个字母为 BB ,那么之后随机到 BBA , BBBA , BBBB 入都一定是 BA 获胜。因此 BA 的获胜概率为 1/4 + 1/4 = 1/2 。

样例说明 2

三个人的获胜概率分别为 4/13 , 17/52 , 19/52 ,注意输出结果四舍五入到两位小数。、

数据范围

100%的数据保证, n , l, m≤ 10.

题解

涉及概率 / 期望的题, 无非就是概率转期望, 期望转概率, DP一下就好了.

比如说这一题, 我们只需要建立trie图, 求出每个节点的经过的期望次数即可.

注意, 当一个节点的儿子为NULL时, 应该把这个概率加到根节点上.

#include <cstdio>
#include <cstring>
#include <deque>
#include <algorithm> const int N = 10, M = 10, L = 10;
int n, l, m;
double p[M];
struct matrix
{
int n;
double a[N * L][N * L + 1];
inline matrix()
{
memset(a, 0, sizeof(a));
}
inline void gauss()
{
for(int i = 0; i < n; ++ i)
{
int p;
for(p = i; p < n && a[p][i] == 0; ++ p);
if(p ^ i)
for(int j = 0; j <= n; ++ j)
std::swap(a[i][j], a[p][j]);
for(int j = 0; j < n; ++ j)
if(j ^ i)
{
double tmp = a[j][i] / a[i][i];
for(int k = 0; k <= n; ++ k)
a[j][k] -= a[i][k] * tmp;
}
}
}
}A;
struct ACautomaton
{
int cnt;
struct node
{
node *suc[10], *fl;
int ed, id;
inline node(int _id)
{
for(int i = 0; i < 26; ++ i)
suc[i] = NULL;
ed = 0;
id = _id;
}
}*rt;
inline ACautomaton()
{
cnt = 0;
rt = new node(cnt ++);
rt->fl = rt;
}
inline int insert(char *str, int len, int id)
{
node *u = rt;
for(int i = 0; i < len; u = u->suc[str[i] - 'A'], ++ i)
if(u->suc[str[i] - 'A'] == NULL)
u->suc[str[i] - 'A'] = new node(cnt ++);
u->ed = 1;
return u->id;
}
inline void build()
{
std::deque<node*> que;
que.clear();
for(int i = 0; i < 26; ++ i)
if(rt->suc[i] != NULL)
rt->suc[i]->fl = rt, que.push_back(rt->suc[i]), A.a[rt->suc[i]->id][0] = p[i];
else if(i < m)
A.a[0][0] += p[i];
for(; ! que.empty(); que.pop_front())
{
node *u = que.front();
for(int i = 0; i < 26; ++ i)
if(u->suc[i] != NULL)
{
if(! u->ed)
A.a[u->suc[i]->id][u->id] = p[i];
node *p = u->fl;
for(; p != rt && p->suc[i] == NULL; p = p->fl);
u->suc[i]->fl = p->suc[i] == NULL ? p : p->suc[i];
que.push_back(u->suc[i]);
}
else
{
u->suc[i] = u->fl->suc[i];
if(u->suc[i] != NULL && ! u->ed)
A.a[u->suc[i]->id][u->id] = p[i];
else if(i < m && ! u->ed)
A.a[0][u->id] += p[i];
}
}
A.n = cnt;
A.a[0][cnt] -= 1;
for(int i = 0; i < cnt; ++ i)
A.a[i][i] += -1;
}
}ACA;
int main()
{ #ifndef ONLINE_JUDGE
freopen("BZOJ1444.in", "r", stdin);
freopen("BZOJ1444.out", "w", stdout);
#endif scanf("%d%d%d", &n, &l, &m);
for(int i = 0; i < m; ++ i)
{
int x, y;
scanf("%d%d\n", &x, &y);
p[i] = (double)x / y;
}
static int ed[N];
for(int i = 0; i < n; ++ i)
{
static char str[L];
scanf("%s", str);
ed[i] = ACA.insert(str, l, i);
}
ACA.build();
A.gauss();
for(int i = 0; i < n; ++ i)
printf("%.2lf\n", A.a[ed[i]][A.n] / A.a[ed[i]][ed[i]] == 0 ? 0 : A.a[ed[i]][A.n] / A.a[ed[i]][ed[i]]);
}

JSOI 2009 BZOJ 1444 有趣的游戏的更多相关文章

  1. BZOJ 1444 有趣的游戏(AC自动机+矩阵快速幂)

    真的是很有趣的游戏... 对每个单词构建好AC自动机后,由于单词都是相同长度的且不同,所以不会出现互相为子串的形式. 那么我们对AC自动机上的节点构建转移矩阵.对于每个单词末尾的节点.该节点的出边仅仅 ...

  2. BZOJ 1444:[JSOI2009]有趣的游戏

    BZOJ 1444:[JSOI2009]有趣的游戏 题目链接 首先我们建出Trie图,然后高斯消元. 我们设\(f_i\)表示经过第\(i\)个点的期望次数: \[ f_x=\sum i\cdot p ...

  3. BZOJ:4820: [Sdoi2017]硬币游戏&&BZOJ:1444: [Jsoi2009]有趣的游戏(高斯消元求概率)

    1444: [Jsoi2009]有趣的游戏 4820: [Sdoi2017]硬币游戏 这两道题都是关于不断随机生成字符后求出现给定字符串的概率的问题. 第一题数据范围较小,将串建成AC自动机以后,以A ...

  4. BZOJ 1444: [Jsoi2009]有趣的游戏 [AC自动机 高斯消元]

    1444: [Jsoi2009]有趣的游戏 题意:每种字母出现概率\(p_i\),有一些长度len的字符串,求他们出现的概率 套路DP的话,\(f[i][j]\) i个字符走到节点j的概率,建出转移矩 ...

  5. BZOJ 1444 [Jsoi2009]有趣的游戏 (AC自动机 + 概率DP + Gauss)

    1444: [Jsoi2009]有趣的游戏 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1382  Solved: 498[Submit][Statu ...

  6. 1444: [Jsoi2009]有趣的游戏

    1444: [Jsoi2009]有趣的游戏 链接 分析: 如果一个点回到0号点,那么会使0号点的概率增加,而0号点的概率本来是1,不能增加,所以这题用期望做. 设$x_i$表示经过i的期望次数,然后初 ...

  7. BZOJ.4820.[SDOI2017]硬币游戏(思路 高斯消元 哈希/AC自动机/KMP)

    BZOJ 洛谷 建出AC自动机,每个点向两个儿子连边,可以得到一张有向图.参照 [SDOI2012]走迷宫 可以得到一个\(Tarjan\)+高斯消元的\(O((nm)^3)\)的做法.(理论有\(6 ...

  8. 【BZOJ1444】[JSOI2009]有趣的游戏(高斯消元,AC自动机)

    [BZOJ1444][JSOI2009]有趣的游戏(高斯消元,AC自动机) 题面 BZOJ 题解 先把\(AC\)自动机构建出来,最好构成\(Trie\)图.然后这样子显然是在一个有向图中有一堆概率的 ...

  9. 【bzoj1444】[Jsoi2009]有趣的游戏

    1444: [Jsoi2009]有趣的游戏 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1007  Solved: 334[Submit][Statu ...

随机推荐

  1. SpringCloud 微服务一:spring boot 基础项目搭建

    spring cloud是建立在spring boot的基础上的,而之前虽然听说过,也随便看了一下spring boot,却没有真正使用,因此还必须先花时间学一下spring boot. spring ...

  2. PHP的抽象类、接口的区别和选择

    1.对接口的使用是通过关键字implements.对抽象类的使用是通过关键字extends.当然接口也可以通过关键字extends继承. 2.接口中不可以声明成员变量(包括类静态变量),但是可以声明类 ...

  3. datagrid的formatter

    1.formatter函数 formatter:function(value,rowData,rowIndex){ return 'xxx'; } 注意: (1)formatter一定要有返回,且返回 ...

  4. 网络安全巧设置 Win2008 R2 防火墙详解(1)

    针对一般中小企业型来说,如果希望对企业网络进行安全管理,不一定非得花高价钱购买专业的防火墙设置,直接借助操作系统本身自带的防火墙功能即可以满足一般企业的应用,今天我们就一起来探究一下Windows S ...

  5. Hyper-V动态迁移中?小心性能损失

    动态迁移是虚拟化技术的一个标志,它允许虚拟机在服务器间进行动态迁移.调节负载平衡.性能管理.备灾管理和数据中心维护.Windows Server 2012 R2中的Hyper-V动态迁移默认功能具备相 ...

  6. IOS开发---菜鸟学习之路--(十五)-如何实现拍照功能

    本章将来讲解下如何实现拍照的功能 我们需要的实现的效果是      好了 直接开始内容吧 首先我们需要新建一个ViewController 就叫AddPictureViewController 然后选 ...

  7. selenium定位下拉菜单好文

    http://www.cnblogs.com/nbkhic/archive/2011/10/23/2221726.html 定位下拉菜单

  8. hnust 懒人多动脑

    问题 F: 懒人得多动脑 时间限制: 1 Sec  内存限制: 128 MB提交: 93  解决: 30[提交][状态][讨论版] 题目描述 小D的家A和学校B都恰好在以点F为焦点的双曲线上,而小D每 ...

  9. 使用 宝塔面板快速部署Java项目

    环境描述: 服务器系统:CentOS7 64位操作系统 面板版本:宝塔6.9.4 Nginx版本:Nginx 1.16 Tomcat版本:Tomcat7 JDK版本:1.8.0_121 环境部署就不用 ...

  10. 【bzoj2186】[Sdoi2008]沙拉公主的困惑 欧拉函数

    题目描述 大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票.房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的 ...