BZOJ:4820: [Sdoi2017]硬币游戏&&BZOJ:1444: [Jsoi2009]有趣的游戏(高斯消元求概率)
1444: [Jsoi2009]有趣的游戏
4820: [Sdoi2017]硬币游戏
这两道题都是关于不断随机生成字符后求出现给定字符串的概率的问题。
第一题数据范围较小,将串建成AC自动机以后,以AC自动机上每个点为一个未知数,列出方程高斯消元求解即可,时间复杂度$O(n^{3}m^{3})$。
#include<queue>
#include<cstdio>
#include<algorithm>
#define MN 21
#define ld double
#define eps 1e-12
using namespace std; struct na{int t[],bo,f;na(){bo=;}}t[MN*MN];
int n,m,l,mo[MN],num=,p[MN],q[MN];
char s[];
int insert(char s[]){
int i=,j=;
for (;s[i];j=t[j].t[s[i]-'A'],i++)
if (!t[j].t[s[i]-'A']) t[j].t[s[i]-'A']=++num;
t[j].bo=;
for (i=;s[i];i++) if (p[s[i]-'A']==) return -;
return j;
}
queue<int> _q;
ld a[MN*MN][MN*MN],S;
ld abs(ld a){return a<?-a:a;}
inline void Gauss(){
int i,j,k;
for (i=;i<=num;i++){
for (j=i;j<=num;j++) if (abs(a[j][i])>eps) break;
for (k=;k<=num+;k++) swap(a[i][k],a[j][k]);
for (j=;j<=num;j++)
if (j!=i)
for (S=a[j][i]/a[i][i],k=;k<=num+;k++) a[j][k]-=S*a[i][k];
}
}
int main(){
register int i,j;
scanf("%d%d%d",&n,&l,&m);
for (i=;i<m;i++) scanf("%d%d",&p[i],&q[i]);
for (i=;i<n;i++) scanf("%s",s),mo[i]=insert(s);
t[].f=;
for (i=;i<m;i++) if (t[].t[i]) _q.push(t[].t[i]),t[t[].t[i]].f=;
while (!_q.empty()){
int k=_q.front();_q.pop();
for (i=;i<m;i++)
if (t[k].t[i]){
for (j=t[k].f;j&&!t[j].t[i];j=t[j].f);
t[t[k].t[i]].f=t[j].t[i];
_q.push(t[k].t[i]);
}
}
for (int k=;k<=num;a[k][k]-=.,k++)
if (!t[k].bo)
for (i=;i<m;i++){
for (j=k;j&&!t[j].t[i];j=t[j].f);
j=t[j].t[i];
a[j][k]+=.*p[i]/q[i];
}
a[][num+]=-;
Gauss();
for (i=;i<n;i++) if (mo[i]==-) puts("0.00");else printf("%.2lf\n",a[mo[i]][num+]/a[mo[i]][mo[i]]+eps);
}
1444: [Jsoi2009]有趣的游戏
第二题,数据范围较大,直接建AC自动机必定会TLE,所以考虑化简。我们需要的只是n个目标状态的答案,而不需要AC自动机上其他点的答案,那么这些点是否可以合并起来,统一考虑呢?
以样例为例:
$S_1=THT,S_2=TTH,S_3=HTT$
考虑一个状态X,表示所有未达到目标状态的字符串。
那么若在X后面接上一个$S_1$,肯定就到达了目标状态,也可能我们还没填完$S_1$我们就达成了目标状态,这些一起考虑起来,可以得到
$$\frac{X}{2^{3}}=S_1+\frac{S_1}{2^{2}}+\frac{S_2}{2}+\frac{S_3}{2^{2}}$$
这是什么意思?XTHT有可能是以下几种情况(我们用$F_{S_i}$表示$S_i$的出现概率)
XTHT =$F_{S_1}$
YTHT HT=$F_{S_1}$ HT(X以TH结尾,即X=YTH)
YTTH T=$F_{S_2}$ T(X以T结尾,即X=YT)
YHTT HT=$F_{S_2}$ HT(X以HT结尾,即X=YHT)
额外多出来的x个字符就需要花费$\frac{1}{2^{x}}$的概率去生成它,也就很显然地对应了上面的式子。
再考虑在X后面接上$S_2$和$S_3$我们又得到两个方程,再加上$\sumF_{S_i}$,一共4(n+1)个方程,解3(n)个变量刚刚好。
另外如果高斯消元的时候你是用的eps来找第一个非0位置,那么很有可能爆精度,这时候你需要将其修改为找到绝对值最大的位置(虽然不知道为什么这样就可以了)。
#include<queue>
#include<cstdio>
#include<algorithm>
#define MN 321
#define ld double
#define eps 1e-12
using namespace std; int n,m,l,mo[MN],num=,ne[MN<<];
char s[MN][MN],c[MN<<];
ld a[MN][MN],S,two[MN];
ld abs(ld a){return a<?-a:a;}
inline void Gauss(){
int i,j,k;
for (i=;i<=num;i++){
for (j=i;j<=num;j++) if (abs(a[j][i])>eps) break;
for (k=;k<=num+;k++) swap(a[i][k],a[j][k]);
for (j=;j<=num;j++)
if (j!=i)
for (S=a[j][i]/a[i][i],k=;k<=num+;k++) a[j][k]-=S*a[i][k]; }
}
int main(){
register int i,j,k,l;
scanf("%d%d",&n,&m);
for (i=;i<=n;i++) scanf("%s",s[i]); for (two[]=,i=;i<=m;i++) two[i]=two[i-]*0.5;
for (i=;i<=n;i++)
for (a[i][]=-two[m],j=;j<=n;j++){
for (k=;k<m;k++) c[k]=s[i][k],c[m+m-k-]=s[j][m-k-];c[m+m]=;
ne[]=-;
for (k=;k<m+m;ne[k]=l+(c[l+]==c[k]),k++)
for (l=ne[k-];l!=-&&c[l+]!=c[k];l=ne[l]);
for (k=ne[k-];k!=-;k=ne[k])
if (k<m) a[i][j]+=two[m--k];
} for (i=;i<=n+;i++) a[][i]=;
num=n;Gauss();
for (i=;i<=n;i++) printf("%.8lf\n",a[i][n+]/a[i][i]+eps);
}
4820: [Sdoi2017]硬币游戏
BZOJ:4820: [Sdoi2017]硬币游戏&&BZOJ:1444: [Jsoi2009]有趣的游戏(高斯消元求概率)的更多相关文章
- [BZOJ 4820] [SDOI2017] 硬币游戏(高斯消元+概率论+字符串hash)
[BZOJ 4820] [SDOI2017] 硬币游戏(高斯消元+概率论+字符串hash) 题面 扔很多次硬币后,用H表示正面朝上,用T表示反面朝上,会得到一个硬币序列.比如HTT表示第一次正面朝上, ...
- BZOJ 1444:[JSOI2009]有趣的游戏
BZOJ 1444:[JSOI2009]有趣的游戏 题目链接 首先我们建出Trie图,然后高斯消元. 我们设\(f_i\)表示经过第\(i\)个点的期望次数: \[ f_x=\sum i\cdot p ...
- BZOJ 1444: [Jsoi2009]有趣的游戏 [AC自动机 高斯消元]
1444: [Jsoi2009]有趣的游戏 题意:每种字母出现概率\(p_i\),有一些长度len的字符串,求他们出现的概率 套路DP的话,\(f[i][j]\) i个字符走到节点j的概率,建出转移矩 ...
- BZOJ 1444 [Jsoi2009]有趣的游戏 (AC自动机 + 概率DP + Gauss)
1444: [Jsoi2009]有趣的游戏 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1382 Solved: 498[Submit][Statu ...
- 1444: [Jsoi2009]有趣的游戏
1444: [Jsoi2009]有趣的游戏 链接 分析: 如果一个点回到0号点,那么会使0号点的概率增加,而0号点的概率本来是1,不能增加,所以这题用期望做. 设$x_i$表示经过i的期望次数,然后初 ...
- 【bzoj3105】[cqoi2013]新Nim游戏 高斯消元求线性基
题目描述 传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同).两个游戏者轮流操作,每次可以选一个火柴堆拿走若干根火柴.可以只拿一根,也可以拿走整堆火柴,但不能同时从 ...
- BZOJ.4820.[SDOI2017]硬币游戏(思路 高斯消元 哈希/AC自动机/KMP)
BZOJ 洛谷 建出AC自动机,每个点向两个儿子连边,可以得到一张有向图.参照 [SDOI2012]走迷宫 可以得到一个\(Tarjan\)+高斯消元的\(O((nm)^3)\)的做法.(理论有\(6 ...
- BZOJ 4820 [SDOI2017] 硬币游戏
Description 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利.大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实在是太单调了.同学们觉得要加强趣味性,所以要找 ...
- ●BZOJ 1444 [Jsoi2009]有趣的游戏
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1444题解.1: 概率dp,矩阵乘法,快速幂. 对所有串建立AC自动机, 那么如果在trie树 ...
随机推荐
- FormData自定义上传图片
由于前段时间的项目中 涉及到图纸的上传 前端大神很随意的扔给我一个页面 让我自己修修改改 找了好几个素材站都没有找到合适的上传插件 最后不得已 用formdata 写了一个 顺便记录下吧 html 代 ...
- Linux 学习记录 一(安装、基本文件操作).
Linux distributions主要分为两大系统,一种是RPM方式安装软件的系统,包括Red Hat,Fedora,SuSE等都是这类:一种则是使用Debian的dpkg方式安装软件的 ...
- geoserver发布地图服务WMTS
WMTS: 切片地图web服务(OpenGIS Web Map Tile Service) WMTS提供了一种采用预定义图块方法发布数字地图服务的标准化解决方案.WMTS弥补了WMS不能提供分块地图的 ...
- Windows as a Service(2)—— 使用WSUS管理Windows10更新
前言 在上一篇Windows as a Service(1)-- Windows 10服务分支中,我和大家分享了Windows 10三个服务分支CB/CBB/LTSB的概念及不同,从这篇文档开始,我将 ...
- JavaScript的DOM编程--02--获取元素节点
如何来获取元素节点: 1) .document.getElementById: 根据 id 属性获取对应的单个节点 2) .document.getElementsByTagName: 根据标签名获取 ...
- 用C#实现微信“跳一跳”小游戏的自动跳跃助手
一.前言: 前段时间微信更新了新版本后,带来的一款H5小游戏“跳一跳”在各朋友圈里又火了起来,类似以前的“打飞机”游戏,这游戏玩法简单,但加上了积分排名功能后,却成了“装逼”的地方,于是很多人花钱花时 ...
- 鸟哥的linux私房菜学习-(三)X Window与文本模式的切换
通常我们也称文本模式为终端机接口, terminal 或 console喔!Linux默认的情况下会提供六个Terminal来让使用者登陆, 切换的方式为使用:[Ctrl] + [Alt] + [F1 ...
- XML文件解析数据结构
最近在解析Android安装包内经过编译的二进制XML文件时想在内存中建立起其对应的树结构. 想了一早晨,思路如下图. 多叉树中的每个节点除了有子节点和兄弟节点以外还有一个指针指向父节点,然后根据状态 ...
- java多线程(八)-死锁问题和java多线程总结
为了防止对共享受限资源的争夺,我们可以通过synchronized等方式来加锁,这个时候该线程就处于阻塞状态,设想这样一种情况,线程A等着线程B完成后才能执行,而线程B又等着线程C,而线程C又等着线程 ...
- vue2.0 资源文件assets和static的区别
资源文件处理 在我们的项目结构里,有两个资源文件的路径,分别是:src/assets 和 static/.那这两个到底有什么区别呢? Webpacked 资源 为了回答这个问题,我们首先需要理解web ...