[Sdoi2017]硬币游戏 [高斯消元 KMP]
[Sdoi2017]硬币游戏
题意:硬币序列,H T等概率出现,\(n \le 300\)个人猜了一个长为$ m \le 300$的字符串,出现即获胜游戏结束。求每个人获胜概率
考场用了[1444: Jsoi200]有趣的游戏的做法,40分
标解好神!
思想就是用N表示所有没有人获胜的状态,然后列方程
对于A,B两个串
例如:
A=TTH, B=HTT
那么N+TTH一定会到终止点,但不一定TTH加完后才停止
NTTH = A + BH + BTH
0.125N = A + 0.75B
获胜概率和为1
n+1个变量 n+1个方程 高斯消元
怎么解释呢?
就是把一些状态的概率用一些变量表示出来了呀
计算系数可以两两用kmp,求B再方程A中的系数:AB连起来求fail,然后得到后缀=前缀了
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=305;
const double eps=1e-10;
inline int read() {
char c=getchar(); int x=0, f=1;
while(c<'0' || c>'9') {if(c=='-')f=-1; c=getchar();}
while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
return x*f;
}
int n, m;
char s[N][N];
double a[N][N], two[N];
namespace kmp {
char s[N<<1];
int fail[N];
void build(char *s, int n) {
fail[1] = 0;
for(int i=2; i<=n; i++) {
int now = fail[i-1];
while(now && s[i] != s[now+1]) now = fail[now];
fail[i] = s[i]==s[now+1] ? now+1 : 0;
}
}
double cal(char *a, char *b) {
int n = m<<1;
for(int i=1; i<=m; i++) s[i] = a[i];
for(int i=1; i<=m; i++) s[i+m] = b[i];
build(s, n);
//for(int i=1; i<=n; i++) printf("%d ", fail[i]); puts("");
int now = fail[n]; double ans = 0;
while(now) ans += two[m-now], now = fail[now];
//printf("ans %lf\n", ans);
return ans;
}
}
void build() {
two[0]=1;
for(int i=1; i<=m; i++) two[i] = two[i-1] * 0.5;
for(int i=1; i<=n; i++) a[n+1][i] = 1;
a[n+1][n+2] = 1;
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) a[i][j] = kmp::cal(s[i], s[j]);
a[i][n+1] = -two[m];
}
}
void gauss(int n) {
//for(int i=1; i<=n; i++) for(int j=1; j<=n+1; j++) printf("%lf%c", a[i][j], j==n+1 ? '\n' : ' ');
for(int i=1; i<=n; i++) {
int r=i;
for(int k=i; k<=n; k++) if(abs(a[k][i]) > abs(a[r][i])) r=k;
if(r != i) for(int j=i; j<=n+1; j++) swap(a[r][j], a[i][j]);
for(int k=i+1; k<=n; k++) {
double t = a[k][i] / a[i][i];
for(int j=i; j<=n+1; j++) a[k][j] -= t * a[i][j];
}
}
for(int i=n; i>=1; i--) {
for(int j=n; j>i; j--) a[i][n+1] -= a[i][j] * a[j][n+1];
a[i][n+1] /= a[i][i];
}
}
int main() {
freopen("game.in", "r", stdin);
freopen("game.out", "w", stdout);
n=read(); m=read();
for(int i=1; i<=n; i++) scanf("%s", s[i]+1);
build();
gauss(n+1);
for(int i=1; i<=n; i++) printf("%.10lf\n", a[i][n+2]);
}
[Sdoi2017]硬币游戏 [高斯消元 KMP]的更多相关文章
- [BZOJ4820][SDOI2017]硬币游戏(高斯消元+KMP)
比较神的一道题,正解比较难以理解. 首先不难得出一个(nm)^3的算法,对所有串建AC自动机,将在每个点停止的概率作为未知数做高斯消元即可. 可以证明,AC自动机上所有不是模式串终止节点的点可以看成一 ...
- [BZOJ 4820] [SDOI2017] 硬币游戏(高斯消元+概率论+字符串hash)
[BZOJ 4820] [SDOI2017] 硬币游戏(高斯消元+概率论+字符串hash) 题面 扔很多次硬币后,用H表示正面朝上,用T表示反面朝上,会得到一个硬币序列.比如HTT表示第一次正面朝上, ...
- BZOJ4820 SDOI2017硬币游戏(概率期望+高斯消元+kmp)
容易想到的做法是建出AC自动机,高斯消元.然而自动机上节点数量是nm的. 注意到我们要求的变量只有n个,考虑将其他不用求的节点合并为一个变量.这个变量即表示随机生成一个串,其不包含任何一个模板串的概率 ...
- 【bzoj3105】[cqoi2013]新Nim游戏 高斯消元求线性基
题目描述 传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同).两个游戏者轮流操作,每次可以选一个火柴堆拿走若干根火柴.可以只拿一根,也可以拿走整堆火柴,但不能同时从 ...
- BZOJ 3105: [cqoi2013]新Nim游戏 [高斯消元XOR 线性基]
以后我也要用传送门! 题意:一些数,选择一个权值最大的异或和不为0的集合 终于有点明白线性基是什么了...等会再整理 求一个权值最大的线性无关子集 线性无关子集满足拟阵的性质,贪心选择权值最大的,用高 ...
- UVA 1358 - Generator(dp+高斯消元+KMP)
UVA 1358 - Generator option=com_onlinejudge&Itemid=8&page=show_problem&category=524& ...
- BZOJ 2466 中山市选2009 树 高斯消元+暴力
题目大意:树上拉灯游戏 高斯消元解异或方程组,对于全部的自由元暴力2^n枚举状态,代入计算 这做法真是一点也不优雅... #include <cstdio> #include <cs ...
- BZOJ.4820.[SDOI2017]硬币游戏(思路 高斯消元 哈希/AC自动机/KMP)
BZOJ 洛谷 建出AC自动机,每个点向两个儿子连边,可以得到一张有向图.参照 [SDOI2012]走迷宫 可以得到一个\(Tarjan\)+高斯消元的\(O((nm)^3)\)的做法.(理论有\(6 ...
- BZOJ4820 Sdoi2017 硬币游戏 【概率期望】【高斯消元】【KMP】*
BZOJ4820 Sdoi2017 硬币游戏 Description 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利.大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实 ...
随机推荐
- Shell菜单脚本
今天在这儿给大家分享一个我简单编写的Shell菜单脚本,傻瓜式的人机交互,人人都可以操作linux. #!/bin/sh #Shell菜单演示 function menu () { cat <& ...
- [国嵌攻略][108][Linux内核链表]
链表简介 链表是一种常见的数据结构,它通过指针将一系列数据节点连接成一条数据链.相对于数组,链表具有更好的动态性,建立链表时无需预先知道数据总量,可以随机分配空间,可以高效地在链表中的任意位置实时插入 ...
- JavaScript八张思维导图—操作符
JS基本概念 JS操作符 JS基本语句 JS数组用法 Date用法 JS字符串用法 JS编程风格 JS编程实践 不知不觉做前端已经五年多了,无论是从最初的jQuery还是现在火热的Angular,Vu ...
- 织梦CMS安装分享插件
获取百度分享按钮织梦系统插件 点击下载:dedecms 5.* 插件 更新日期:2011.09.05 1.下载百度分享插件的织梦cms版本. 2.使用管理员账号登录您的站点后台管理中心,单击" ...
- 【开发技术】Beyond Compare
黑色表示左右两侧的文件(夹)是一样的; 紫色表示右(左)侧是完全没有的,这时我们右击这个文件(夹),选择“复制到右(左)侧”即可: 红色表示两边都有这个文件(夹),但不完全相同,这时你就要权衡一下修改 ...
- 007-declare 声明变量的类型
declare [+/-] [选项] 变量名 - 给变量设定类型 + 取消变量的类型 -a 将变量声明为数组型 -i 将变量声明为整形 -x 将变量声明成环境变量 -r 将变量声明为只读变量 -p 显 ...
- 输入和输出--java的NIO
Java的NIO 实际开发中NIO使用到的并不多,我并不是说NIO使用情景不多,是说我自己接触的并不是很多,前面我在博客园和CSDN上转载了2篇别人写的文章,这里来大致总结下Java的NIO,大概了解 ...
- String.Format 格式化货币的小问题
今天在开发过程中,遇到一件让我觉得比较纳闷的事情:用String.Format 格式化充值金额的时候,我这样处理: String.Format("{0:C2}", dr[" ...
- android adapter 中添加OnClickListener事件
public class SearchAutoAdapter extends BaseAdapter { private OnClickListener mOnClickListener; publi ...
- DNS服务器解析域名的过程
最近在读许令波老师的<深入分析Java Web技术内幕>,算是对DNS服务器域名解析有个大体的理解,以下的内容来自个人对书中内容的整理 1.什么是域名解析? 当我们在浏览器的地址栏输入一个 ...