4820: [Sdoi2017]硬币游戏

Time Limit: 10 Sec  Memory Limit: 128 MB

Description

周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利。大家纷纷觉得这个游戏非常符
合同学们的特色,但只是扔硬币实在是太单调了。同学们觉得要加强趣味性,所以要找一个同学扔很多很多次硬币
,其他同学记录下正反面情况。用H表示正面朝上,用T表示反面朝上,扔很多次硬币后,会得到一个硬币序列。比
如HTT表示第一次正面朝上,后两次反面朝上。但扔到什么时候停止呢?大家提议,选出n个同学,每个同学猜一个
长度为m的序列,当某一个同学猜的序列在硬币序列中出现时,就不再扔硬币了,并且这个同学胜利,为了保证只
有一个同学胜利,同学们猜的n个序列两两不同。很快,n个同学猜好序列,然后进入了紧张而又刺激的扔硬币环节
。你想知道,如果硬币正反面朝上的概率相同,每个同学胜利的概率是多少。

Input

第一行两个整数n,m。
接下里n行,每行一个长度为m的字符串,表示第i个同学猜的序列。
1<=n,m<=300

Output

输出n行,第i行表示第i个同学胜利的概率。
输出与标准输出的绝对误差不超过10^-6即视为正确。

Sample Input

3 3
THT
TTH
HTT

Sample Output

0.3333333333
0.2500000000
0.4166666667
 
题解:
生无可恋.jpg
在我做过的题里继小凸玩密室又一神题啊……我可能学了假的概率DP
上来我们可以发现这本是一道字符集为2的AC自动机的DP,迅速码好读入和处理fail指针。
然后我们继续套路,发现这个获胜概率在Trie图上互相牵制不能递推,所以我们要用高斯消元。
……高斯消元?
如果我们对于每个AC自动机的节点都这样做的话,仅时间复杂度就变成了O(3006),直接螺旋上天了。
那么我们只能不考虑每个节点,而是考虑每个串了。
设p[i]为第i个同学获胜的概率,也就是说第一个匹配到第i个串的概率。
首先我们可以列出第一个方程:Σp[i]=1.0
那么我们考虑,在一个不是单词节点的节点,假设已经经过的字符状态为S,
如果我们向后面添加m个字符,那么显然,由于我们是完全随机添加的,所以匹配到每个串i的概率都是一样的,我们设为H。
不难看出,如果我们匹配到i,那么这种添加方式可以包含所有匹配到i的情况。
但是这里H不一定等于p[i]:我们经过每个非单词节点的概率也不一定一样;
并且同时,由于我们之前已经匹配了状态为S的一些字符,我们可能在添加不到m个字符时就匹配到了某个串j(j可以等于i)
如果在某个节点加上字符串i的前k个字符后就已经到达了字符串j的终止节点,那么j的后k个字符必然等于i的前k个字符.
在匹配上j后,(虽然继续匹配是非法的,但是我们要减去这种非法状态,所以我们还要计算这种状态发生的概率.)
我们还要继续生成字符使得接下来m-k的字符等于串i的后m-k个字符,也就是说,p[i]应该在H的基础上减去p[j]*(1/2)m-k
这里的“前k个字符重叠”,我们可以利用KMP的失配指针来处理。
(其实这里的处理方法有很多,除了kmp,hash也可以,只要能找出两串的重叠部分即可)
那么最后,我们可以列出方程:p[i]=H-Σp[j]*(1/2)m-k,移项得p[i]+Σp[j]*(1/2)m-k-H=0
再加上一开始的方程Σp[i]=1.0,我们就可以对n+1个变量列出n+1个方程来解方程了!
代码见下:
 #include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=;
int n,l,cnt,fail[N<<];
char s[N][N],str[N<<];
double f[N][N];
inline void kmp()
{
register int i,j,len;
for(i=,j=,len=(l<<);i<=len;++i)
{
while(j&&str[j+]!=str[i])j=fail[j];
j=(str[j+]==str[i])?j+:j,fail[i]=j;
}
}
void Swap(int a,int b)
{for(register int i=;i<=cnt+;++i)swap(f[a][i],f[b][i]);}
void Execution(int a,int b,double t)
{for(register int i=;i<=cnt+;++i)f[a][i]+=f[b][i]*t;}
inline void gauss()
{
register int i,j,k;
for(i=;i<=cnt;++i)
{
for(j=i+;j<=cnt;++j)if(fabs(f[i][i])<fabs(f[j][i]))Swap(i,j);
for(j=;j<=cnt;++j)if(j!=i)Execution(j,i,-f[j][i]/f[i][i]);
}
for(i=;i<=cnt;++i)f[i][cnt+]/=f[i][i];
}
int main()
{
scanf("%d%d",&n,&l);register int i,j,k;
for(i=;i<=n;++i)scanf("%s",s[i]+);
for(i=;i<=n;++i)
for(j=;j<=n;++j)
{
for(k=;k<=l;++k)str[k]=s[i][k],str[l+k]=s[j][k];
for(kmp(),k=fail[l<<];k;k=fail[k])
if(k<l)f[i][j]+=pow(0.5,l-k);
}
for(i=;i<=n;++i)f[i][i]+=1.0,f[i][n+]-=1.0;//n+1代表未知变量H
for(i=,f[n+][n+]=1.0;i<=n;++i)f[n+][i]=1.0;
cnt=n+;gauss();
for(i=;i<=n;++i)printf("%.10lf\n",f[i][cnt+]);
}
 

[BZOJ4820]硬币游戏 KMP+高斯消元的更多相关文章

  1. 【BZOJ4820】[SDOI2017]硬币游戏(高斯消元)

    [BZOJ4820][SDOI2017]硬币游戏(高斯消元) 题面 BZOJ 洛谷 题解 第一眼的感觉就是构\(AC\)自动机之后直接高斯消元算概率,这样子似乎就是\(BZOJ1444\)了.然而点数 ...

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

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

  3. P3706-[SDOI2017]硬币游戏【高斯消元,字符串hash】

    正题 题目链接:https://www.luogu.com.cn/problem/P3706 题目大意 给出 \(n\) 个长度为 \(m\) 的 \(H/T\) 串. 开始一个空序列,每次随机在后面 ...

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

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

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

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

  6. LA3490 Generator(KMP + 高斯消元)

    题意 一开始给你一个长为 \(S\) 的字符串. 从空串开始,不断在后面添加一个 \([A, A + n]\) 的一个字符. 第一次包含 \(S\) 的时候会停止添加.问期望的添加次数. 有 \(T\ ...

  7. 【BZOJ 4171】 4171: Rhl的游戏 (高斯消元)

    4171: Rhl的游戏 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 74  Solved: 33[Submit][Status][Discuss] ...

  8. bzoj 4820: [Sdoi2017]硬币游戏【kmp+高斯消元】

    有点神,按照1444的做法肯定会挂 注意到它的概率是相同的,所以可以简化状态 详见http://www.cnblogs.com/candy99/p/6701221.html https://www.c ...

  9. [BZOJ4820][SDOI2017]硬币游戏(高斯消元+KMP)

    比较神的一道题,正解比较难以理解. 首先不难得出一个(nm)^3的算法,对所有串建AC自动机,将在每个点停止的概率作为未知数做高斯消元即可. 可以证明,AC自动机上所有不是模式串终止节点的点可以看成一 ...

随机推荐

  1. Python学习过程笔记整理(一)

    编码方式 -Utf8编码方式:# -*- coding: utf-8 -*- 注释 -行注释 # -块注释 '''...'''或"""...""&qu ...

  2. Centos6.8操作防火墙

    设置防火墙iptables开放3306接口 在/etc/sysconfig下面有个iptables文件,在控制台输入命令 iptables -I INPUT -p tcp --dport 3306 - ...

  3. yum指令常用参数说明

    1.使用YUM查找软件包 命令:yum search 2.列出所有可安装的软件包 命令:yum list 3.列出所有可更新的软件包 命令:yum list updates 4.列出所有已安装的软件包 ...

  4. Unity3d — — UGUI之Box Collider自适应大小

    NGUI下给Sprite/image添加collider后能自适应大小,但是在UGUI下Collider是默认在(0,0)位置,size为0 因此写了个简单的脚本,效果如下(最后附代码) 1.如下图添 ...

  5. .Net 如何访问主流的各大数据库

    做过开发的都知道,.NET基本可以理解是和MSSQL,windows服务器属于一个好的搭档,正如PHP和MYSQL,LIUNX等也可以理解是一个完美搭配:但是在实际的开发中并不完全是这样的,如果你是学 ...

  6. 单纯形法MATALAB实现

    参考单纯形法的步骤,MATALAB中的实现如下(求极小值): 注:对于极大值的求解,只需要对目标函数添加负号,求解出来的\(X\),再带入原目标函数即可. function [ X, z ] = si ...

  7. 2019第十届蓝桥杯C++B组题解(赛后重写的,不确保答案正确性,仅供参考)

    先说一下这次的感受吧,我们考场比较乱,开始比赛了,还有的电脑有故障,(向这些人发出同情),第一次认真参加比赛,真正比赛的时候感觉没有那么正式,很乱,各种小问题,(例如博主就没找到题目在哪里,找到后又不 ...

  8. fiddler常识汇总

    Fiddler 抓包工具总结   名称 含义 # 抓取HTTP Request的顺序,从1开始,以此递增 Result HTTP状态码 Protocol 请求使用的协议,如HTTP/HTTPS/FTP ...

  9. 始入OO课程的殿堂,初识面向对象的奥妙——OO第一次博客总结

    当我满怀期待叩开OO的大门,却发现宝藏藏在层层阻难之后 第一次作业 1.度量分析 >关于第一次作业的metrics图分析没有出现标红的McCabe Cyclomatic Complexity或者 ...

  10. 《[C#] int与System.Int32有什么区别》

    最近园里的TeamOne写了一篇<[C#] int与System.Int32有什么区别>,发现里面有不少精彩的评论,所以忍不住想这篇文章总结一下:> 本文的主要参考资料: 1.< ...