题目大意:给你$N$个长度相等且互不相同的模式串,现在有一个字符串生成器会不断生成字符,其中每个字符出现的概率是$p_{i}/q_{i}$,当生成器生成的字符串包含了某个模式串,则拥有该模式串的玩家胜利,然后游戏立即结束,求每个玩家获胜的概率 $N<=10$

首先建出$Trie$图

接着设$f[i]$表示匹配时停在i的概率,可得$f[ch{k}]+=f[i]*p_{k}/q_{k}$

由于$N$很小,可以构建$dp$转移的邻接矩阵,由于生成器生成的串是无限长的,相当于把矩阵乘了无限次幂

可以耍赖一点...把矩阵自乘很多次,反正是保留小数卡精度过

正确的做法呢,就是利用等比数列求极限的方法,即$1/(1-p)$,1在这里是单位矩阵,$p$是邻接矩阵

然后对$(1-p)$这个矩阵求逆即可

 #include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define NN 105
#define maxn 100000
#define ll long long
#define dd double
#define uint unsigned int
#define mod 1000000007
#define idx(X) (X-'A')
#define eps (1e-9)
using namespace std; int n,m;
int ed[NN];
int p[],q[],L,num; struct M{
dd f[NN][NN*];
friend M operator * (const M &a,const M &b){
M ret;memset(&ret,,sizeof(ret));
for(int i=;i<n;i++)
for(int j=;j<n;j++)
for(int k=;k<n;k++)
ret.f[i][j]+=a.f[i][k]*b.f[k][j];
return ret;
}
int Gauss()
{
int nn=n*;
for(int i=;i<n;i++)
f[i][i+n]=;
for(int i=;i<n;i++)
{
for(int j=i;j<n;j++)
if(fabs(f[j][i])>eps){
for(int k=;k<nn;k++)
swap(f[i][k],f[j][k]);
break;
}
if(fabs(f[i][i])<eps) return ;
dd r=1.0/f[i][i];
for(int j=i;j<nn;j++)
f[i][j]*=r;
for(int j=;j<n;j++)
if(j!=i){
r=f[j][i];
for(int k=i;k<nn;k++)
f[j][k]=f[j][k]-r*f[i][k];
}
}
for(int i=;i<n;i++)
for(int j=;j<n;j++)
f[i][j]=f[i][j+n];
return ;
}
}; struct AC{
int ch[NN][],fail[NN],tot,win[NN];
void Build_Trie(char *str,int len,int id)
{
int x=;
for(int i=;i<=len;i++){
if(!ch[x][idx(str[i])])
ch[x][idx(str[i])]=++tot;
x=ch[x][idx(str[i])];
}ed[id]=x;win[x]=;
}
void Build_Fail()
{
queue<int>q;
for(int i=;i<m;i++)
if(ch[][i]) q.push(ch[][i]);
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=;i<m;i++)
{
if(ch[x][i]){
fail[ch[x][i]]=ch[fail[x]][i];
q.push(ch[x][i]);
}else{
ch[x][i]=ch[fail[x]][i];
}
}
}
}
void Build_Martix(M &S)
{
for(int x=;x<=tot;x++)
if(!win[x]){
for(int i=;i<m;i++)
S.f[ch[x][i]][x]+=1.0*p[i]/q[i];
}
for(int i=;i<n;i++)
for(int j=;j<n;j++)
if(i!=j) S.f[i][j]=-S.f[i][j];
else S.f[i][j]=1.0-S.f[i][j];
}
}ac;
M ans,ni; int main()
{
//freopen("t1.in","r",stdin);
scanf("%d%d%d",&num,&L,&m);
for(int i=;i<m;i++)
scanf("%d%d",&p[i],&q[i]);
char str[];
for(int i=;i<=num;i++){
scanf("%s",str+);
ac.Build_Trie(str,L,i);}
ac.Build_Fail();
n=ac.tot+;
ac.Build_Martix(ans);
ans.Gauss();
for(int i=;i<=num;i++)
printf("%.2lf\n",ans.f[ed[i]][]);
return ;
}

BZOJ 1444 [JSOI2009]有趣的游戏 (Trie图/AC自动机+矩阵求逆)的更多相关文章

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

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

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

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

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

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

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

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

  5. ●BZOJ 1444 [Jsoi2009]有趣的游戏

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1444题解.1: 概率dp,矩阵乘法,快速幂. 对所有串建立AC自动机, 那么如果在trie树 ...

  6. bzoj 1444: [Jsoi2009]有趣的游戏【AC自动机+dp+高斯消元】

    https://blog.sengxian.com/solutions/bzoj-1444 orz 一直是我想错了,建出AC自动机之后,实际上这个定义是设f[i]为经过i节点的 * 期望次数 * ,因 ...

  7. BZOJ 1444 [JSOI2009]有趣的游戏 (AC自动机、概率与期望DP、矩阵乘法)

    诶这题洛谷居然没有??? 题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1444 题解: 我见到主要有三种做法. 一是矩阵乘法.设\(d ...

  8. BZOJ 1444: [Jsoi2009]有趣的游戏 AC自动机+概率与期望+矩阵乘法

    这道题还比较友好~首先,构建出来 $AC$ 自动机,那么我们要求的就是从 $0$ 号点走无限次走到一个终止节点的概率. 考虑构建转移矩阵 $M,$ $M_{i,j}$ 表示节点 $i$ 转移到节点 $ ...

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

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

随机推荐

  1. WePy--记录使用过程中的一些坑

    讲真, 官方文档还是要好好看, 都是细节啊... 1- 使用wepy框架中封装好的小程序api  <wepy 对小程序的API进行Promise处理>   ①: 首先需要声明 开启使用we ...

  2. JS中的异步

    Hello,日常更新的我“浪”回来了!!! JS中有三座高山:异步和单线程.作用域和闭包.原型原型链 今天“浪”的主题是JS中的异步和单线程的问题. 主要从这三个方面入手 一.什么是异步(与同步作比较 ...

  3. CF508E (贪心+搜索+构造)

    题目大意:让你构造一个括号序列,括号匹配的方式类似于栈,给出从左数每个括号 到和它匹配的右括号的 最小和最大距离,让你输出一个合法括号序列 看错题了以为是二分图,然后写了搜索 贪心发现如果距离往小了填 ...

  4. C语言实现将一个整形数转换为两个字节16进制

    有时候要用到这个转换,这里记录一下,例如把 int a = 164 转换储存在数组里为 uint8_t b[0]=0x00  , b[1]=0xA4 . 很简单,转换如下: b[0] = a > ...

  5. STM32 软件复位并模拟USB拔插

    最近做了个USB跟上位机的通信,需要软件对MCU进行复位,复位后如果USB没有拔插,PC就不会重新枚举USB为了解决这个问题,我做了软件复位跟,软件模拟USB拔插. 这里我用的是HAL库的软件复位,复 ...

  6. 工具-VS使用GIT工具

    由于VS中集成了GIT插件,本机安装了GIT工具和TortoiseGit工具,造成在VS中GIT无法同步,于是将TortoiseGit卸载,再次启用VS中的GIT插件,重新初始化GIT文件夹,问题解决 ...

  7. CODEVS——T 1269 匈牙利游戏 2012年CCC加拿大高中生信息学奥赛

    http://codevs.cn/problem/1269/  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解       题目描述 Descript ...

  8. POJ——T2352 Stars

    http://poj.org/problem?id=2352 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 46592   ...

  9. 51nod-1346: 递归

    [传送门:51nod-1346] 简要题意: 给出一个式子a[i][j]=a[i-1][j]^a[i][j-1] 给出a[1][i],a[i][1](2<=i<=131172) 有n个询问 ...

  10. iOS:简单使用UIAlertVIew和UIActionSheet

    做iOS开发的同学想必都用过UIAlertVIew或者UIActionSheet.UIAlertVIew 可以弹出一个出现在屏幕中间的提示视图,给用户展示信息,并让用户自己选择操作,UIActionS ...