4820: [Sdoi2017]硬币游戏
4820: [Sdoi2017]硬币游戏
分析:
期望dp+高斯消元。
首先可以建出AC自动机,Xi表示经过节点i的期望次数,然后高斯消元,这样点的个数太多,复杂度太大。但是AC自动机上末尾节点只有n个,并且只有n个有用。所以考虑优化一下。
一个串内部的转移是没有必要的,考虑转移到结尾节点的转移。
当前的一个串S如果加入一个字符串T,变成ST,那么一定会结束,因为T这个字符串出现了。但是可能在T的某个前缀就出现了, 即存在一个字符串的后缀是T的前缀,那么统计出这样的转移,然后高斯消元。
加了eps后WA了?
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cctype>
#include<set>
#include<vector>
#include<queue>
#include<map>
#define fi(s) freopen(s,"r",stdin);
#define fo(s) freopen(s,"w",stdout);
using namespace std;
typedef long long LL; inline int read() {
int x=,f=;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
for(;isdigit(ch);ch=getchar())x=x*+ch-'';return x*f;
} const int N = ;
char s[N][N];
int p[N][N], n, m;
double mi[N], A[N][N]; void init(char *s,int *p) {
for (int i = ; i <= m; ++i) {
int j = p[i - ];
while (j && s[j + ] != s[i]) j = p[j];
if (s[j + ] == s[i]) j ++;
p[i] = j;
}
}
double Calc(char *a,char *b,int *p,bool f) {
int j = ;
for (int i = ; i <= m; ++i) {
while (j && b[i] != a[j + ]) j = p[j];
if (b[i] == a[j + ]) j ++;
}
if (f) j = p[j];
double res = ;
while (j) res += mi[m - j], j = p[j];
return res;
}
void Gauss() {
for (int k = ; k <= n; ++k) {
int r = k;
for (int i = k + ; i <= n; ++i) if (fabs(A[i][k]) > fabs(A[r][k])) r = i;
if (r != k) for (int j = ; j <= n + ; ++j) swap(A[r][j], A[k][j]);
for (int i = k + ; i <= n; ++i) {
if (fabs(A[i][k]) > ) {
double t = A[i][k] / A[k][k];
for (int j = ; j <= n + ; ++j) A[i][j] -= t * A[k][j];
}
}
}
for (int i = n; i >= ; --i) {
for (int j = i + ; j <= n; ++j) A[i][n + ] -= A[i][j] * A[j][n + ];
A[i][n + ] /= A[i][i];
}
}
int main() {
n = read(), m = read();
for (int i = ; i <= n; ++i) {
scanf("%s", s[i] + );
init(s[i], p[i]);
}
mi[] = ;
for (int i = ; i <= m; ++i) mi[i] = mi[i - ] * 0.5;
for (int i = ; i <= n + ; ++i) A[][i] = ;
for (int i = ; i <= n; ++i) {
A[i][] = -mi[m]; A[i][i] = 1.0;
for (int j = ; j <= n; ++j)
A[i][j] += Calc(s[i], s[j], p[i], i == j); // 计算字符串i转移到j的概率,即求i的前缀等于j的后缀
}
Gauss();
for (int i = ; i <= n; ++i) printf("%.10lf\n",A[i][n + ]);
return ;
}
4820: [Sdoi2017]硬币游戏的更多相关文章
- BZOJ:4820: [Sdoi2017]硬币游戏&&BZOJ:1444: [Jsoi2009]有趣的游戏(高斯消元求概率)
1444: [Jsoi2009]有趣的游戏 4820: [Sdoi2017]硬币游戏 这两道题都是关于不断随机生成字符后求出现给定字符串的概率的问题. 第一题数据范围较小,将串建成AC自动机以后,以A ...
- [BZOJ 4820] [SDOI2017] 硬币游戏(高斯消元+概率论+字符串hash)
[BZOJ 4820] [SDOI2017] 硬币游戏(高斯消元+概率论+字符串hash) 题面 扔很多次硬币后,用H表示正面朝上,用T表示反面朝上,会得到一个硬币序列.比如HTT表示第一次正面朝上, ...
- BZOJ 4820 [SDOI2017] 硬币游戏
Description 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利.大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实在是太单调了.同学们觉得要加强趣味性,所以要找 ...
- BZOJ.4820.[SDOI2017]硬币游戏(思路 高斯消元 哈希/AC自动机/KMP)
BZOJ 洛谷 建出AC自动机,每个点向两个儿子连边,可以得到一张有向图.参照 [SDOI2012]走迷宫 可以得到一个\(Tarjan\)+高斯消元的\(O((nm)^3)\)的做法.(理论有\(6 ...
- BZOJ 4820 [Sdoi2017]硬币游戏 ——期望DP 高斯消元
做法太神了,理解不了. 自己想到的是建出AC自动机然后建出矩阵然后求逆计算,感觉可以过$40%$ 用一个状态$N$表示任意一个位置没有匹配成功的概率和. 每种匹配不成功的情况都是等价的. 然后我们强制 ...
- bzoj 4820: [Sdoi2017]硬币游戏【kmp+高斯消元】
有点神,按照1444的做法肯定会挂 注意到它的概率是相同的,所以可以简化状态 详见http://www.cnblogs.com/candy99/p/6701221.html https://www.c ...
- [Sdoi2017]硬币游戏 [高斯消元 KMP]
[Sdoi2017]硬币游戏 题意:硬币序列,H T等概率出现,\(n \le 300\)个人猜了一个长为$ m \le 300$的字符串,出现即获胜游戏结束.求每个人获胜概率 考场用了[1444: ...
- 【BZOJ4820】[SDOI2017]硬币游戏(高斯消元)
[BZOJ4820][SDOI2017]硬币游戏(高斯消元) 题面 BZOJ 洛谷 题解 第一眼的感觉就是构\(AC\)自动机之后直接高斯消元算概率,这样子似乎就是\(BZOJ1444\)了.然而点数 ...
- BZOJ4820 Sdoi2017 硬币游戏 【概率期望】【高斯消元】【KMP】*
BZOJ4820 Sdoi2017 硬币游戏 Description 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利.大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实 ...
随机推荐
- 可以简易设置文字内边距的EdgeInsetsLabel
可以简易设置文字内边距的EdgeInsetsLabel 最终效果: 源码: EdgeInsetsLabel.h 与 EdgeInsetsLabel.m // // EdgeInsetsLabel.h ...
- 如何生成.p12文件
如何生成.p12文件 1. 打开钥匙串 2. 钥匙串选登录,种类选证书 3. 选择开发者,然后导出证书 4. 存储证书 5. 选择存储的时候会提示输入证书的密码,当然,也可以不用输入密码 6. 点击上 ...
- [翻译] DraggableYoutubeFloatingVideo
DraggableYoutubeFloatingVideo DraggableYoutubeFloatingVideo allows you to play videos on a floating ...
- UNIX高级环境编程(5)Files And Directories - 文件相关时间,目录文件相关操作
1 File Times 每个文件会维护三个时间字段,每个字段代表的时间都不同.如下表所示: 字段说明: st_mtim(the modification time)记录了文件内容最后一次被修改的时 ...
- Redis学习---Ubuntu下Redis的安装
Ubuntu系统安装 Linux 系统安装[Ubuntu] 安装/启动Redis 要在 Ubuntu 上安装 Redis,打开终端,然后输入以下命令: 升级软件管理模块apt: sudo apt-ge ...
- Linux系统设置运行级别
设置运行级别 查看开机加载级别:7个级别 规范场景默认都是3 cat /etc/inittab --> 系统开机启动加载的文件,可以设置运行级别 # Default runlev ...
- Linux配置自动发送邮件
需要的工具:sendEmail 和 linux自带的定时工具:crontab 1.sendEmail的使用: 具体参数解释: -f zhangshibo706@163.com 发件人邮箱 -t 453 ...
- 使用yii AR 完成单个表的CURD操作
什么是AR(ActiveRecord) Active Record (活动记录,以下简称AR)提供了一个面向对象的接口, 用以访问数据库中的数据.一个 AR 类关联一张数据表, 每个 AR 对象对应表 ...
- Linux--面试题-01
1. 在Linux系统中,以 文件 方式访问设备 . 2. Linux内核引导时,从文件 /etc/fstab 中读取要加载的文件系统. 3. Linux文件系统中每个文件用 i节点 来标识. 4. ...
- 【教程】【FLEX】#006 控件位置的拖动
上一篇笔记学习了怎么从 把一个控件拖放到另外一个控件里面(即 A --> B里面). 而现在呢,则是学习 怎么把 A 拖到另外一个位置. (A -->A位置改变): 先说一下实现的思路( ...