P3706-[SDOI2017]硬币游戏【高斯消元,字符串hash】
正题
题目链接:https://www.luogu.com.cn/problem/P3706
题目大意
给出 \(n\) 个长度为 \(m\) 的 \(H/T\) 串。
开始一个空序列,每次随机在后面加一个 \(H/T\) ,求每个串第一次出现的概率。
\(1\leq n,m\leq 300\)
解题思路
数据范围显然不能在AC自动机上高斯消元,所以得考虑别的方法。
考虑一个很妙的做法,设一个状态\(N\)表示目前还没有匹配完成的串,然后考虑串\(A=HHT\)和串\(B=THH\),那么在\(N\)后面直接插入一个\(A\)的概率就是\(p(N+A)=p(N)\times 2^{-m}\)
但是考虑到有可能\(N\)先拼出了\(B\)然后再拼出\(A\),此时考虑\(B\)的后缀对应\(A\)前缀的有\(H,HH\)。那么就有
\]
这样不难发现对于别的串如果它的一些后缀是这个串的前缀那么就会产生一些概率,用字符串\(hash\)匹配即可。
然后会发现还是少了一个方程,最后一个就是所有串的概率和为\(1\)就好了。
这样就有\(n+1\)个方程了。
时间复杂度:\(O(n^2m+n^3)\)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ull unsigned long long
using namespace std;
const int N=310;
const ull g=131;
int n,m;
double a[N][N],b[N],pw[N];
ull h[N][N],p[N];char s[N];
ull geth(int x,int l,int r)
{return h[x][r]-h[x][l-1]*p[r-l+1];}
void Gauss(int n){
for(int i=1;i<=n;i++){
int z=i;
for(int j=i+1;j<=n;j++)
if(a[j][i]>a[z][i])z=i;
swap(a[i],a[z]);
double x=a[i][i];b[i]/=x;
for(int j=i;j<=n;j++)a[i][j]/=x;
for(int j=i+1;j<=n;j++){
double rate=-a[j][i];
for(int k=i;k<=n;k++)
a[j][k]+=rate*a[i][k];
b[j]+=rate*b[i];
}
}
for(int i=n;i>=1;i--){
for(int j=1;j<i;j++){
b[j]-=a[j][i]*b[i];
a[j][i]=0;
}
}
return;
}
int main()
{
scanf("%d%d",&n,&m);p[0]=1;pw[0]=1;
for(int i=1;i<=m;i++)
pw[i]=pw[i-1]*0.5,p[i]=p[i-1]*g;
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++)
h[i][j]=h[i][j-1]*g+s[j];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=m;k++)
if(geth(i,1,k)==geth(j,m-k+1,m))
a[i][j]+=pw[m-k];
for(int i=1;i<=n;i++)
a[i][n+1]=-pw[m],a[n+1][i]=1;
b[n+1]=1;Gauss(n+1);
for(int i=1;i<=n;i++)
printf("%.12lf\n",b[i]);
return 0;
}
P3706-[SDOI2017]硬币游戏【高斯消元,字符串hash】的更多相关文章
- [BZOJ 4820] [SDOI2017] 硬币游戏(高斯消元+概率论+字符串hash)
[BZOJ 4820] [SDOI2017] 硬币游戏(高斯消元+概率论+字符串hash) 题面 扔很多次硬币后,用H表示正面朝上,用T表示反面朝上,会得到一个硬币序列.比如HTT表示第一次正面朝上, ...
- [Sdoi2017]硬币游戏 [高斯消元 KMP]
[Sdoi2017]硬币游戏 题意:硬币序列,H T等概率出现,\(n \le 300\)个人猜了一个长为$ m \le 300$的字符串,出现即获胜游戏结束.求每个人获胜概率 考场用了[1444: ...
- [BZOJ4820][SDOI2017]硬币游戏(高斯消元+KMP)
比较神的一道题,正解比较难以理解. 首先不难得出一个(nm)^3的算法,对所有串建AC自动机,将在每个点停止的概率作为未知数做高斯消元即可. 可以证明,AC自动机上所有不是模式串终止节点的点可以看成一 ...
- 洛咕 P3706 [SDOI2017]硬币游戏
假设f[i]是第i个同学胜利的概率,也就是随机序列第一个匹配到s[i]的概率 假设前面有一个字符串\(S\),(假设无限长但没有匹配),现在往后面要加上第i个串\(s[i]\),这个的概率设为\(P_ ...
- 【bzoj3105】[cqoi2013]新Nim游戏 高斯消元求线性基
题目描述 传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同).两个游戏者轮流操作,每次可以选一个火柴堆拿走若干根火柴.可以只拿一根,也可以拿走整堆火柴,但不能同时从 ...
- BZOJ 3105: [cqoi2013]新Nim游戏 [高斯消元XOR 线性基]
以后我也要用传送门! 题意:一些数,选择一个权值最大的异或和不为0的集合 终于有点明白线性基是什么了...等会再整理 求一个权值最大的线性无关子集 线性无关子集满足拟阵的性质,贪心选择权值最大的,用高 ...
- 洛谷P3706 [SDOI2017]硬币游戏(概率生成函数+高斯消元)
题面 传送门 题解 不知道概率生成函数是什么的可以看看这篇文章,题解也在里面了 //minamoto #include<bits/stdc++.h> #define R register ...
- BZOJ 2466 中山市选2009 树 高斯消元+暴力
题目大意:树上拉灯游戏 高斯消元解异或方程组,对于全部的自由元暴力2^n枚举状态,代入计算 这做法真是一点也不优雅... #include <cstdio> #include <cs ...
- BZOJ:4820: [Sdoi2017]硬币游戏&&BZOJ:1444: [Jsoi2009]有趣的游戏(高斯消元求概率)
1444: [Jsoi2009]有趣的游戏 4820: [Sdoi2017]硬币游戏 这两道题都是关于不断随机生成字符后求出现给定字符串的概率的问题. 第一题数据范围较小,将串建成AC自动机以后,以A ...
随机推荐
- open62541(opcua)传输延迟探索小记
缘起 将open62541作为中间件使用代替自定义数据的RPC,client通过订阅valueChange来接收数据.使用时发现有一些问题: 前后两次产生的数据相同时,不会触发valueChange ...
- 【spring】69道Spring面试题和答案
原文地址:http://ifeve.com/spring-interview-questions-and-answers/ 目录 Spring 概述 依赖注入 Spring beans Spring注 ...
- 这样设计 Java 异常更优雅
转自:lrwinx.github.io/2016/04/28/如何优雅的设计java异常/ 导语 异常处理是程序开发中必不可少操作之一,但如何正确优雅的对异常进行处理确是一门学问,笔者根据自己的开发经 ...
- linux下设备驱动的结构&编译&加载
构造和运行模块 insmod modprobe rmmod 用来装载模块到正运行的内核和移除模块的用户空间工具. #include<linux/init.h> module_init(in ...
- kafka零数据丢失的配置方案
讨论一下kafka参数的配置 1.acks 参数配置 acks这个参数有三个值:0,1,-1,但是不用的参数对应的含义不同,那如果我们想要保证数据不丢失,acks 值应该设置为哪个参数呢? 0:代表生 ...
- Redis(三):新数据类型
配置文件redis.conf详解 bind=127.0.0.1 # 表示只能在本机中访问redis,将该行注释掉,即可接收任何IP地址的访问 protected-mode # 设置为no,表示关闭保护 ...
- BST B树 B+树
二叉排序树/二叉搜索树 (BST) 定义 左子树节点值<根节点值<右子树节点值 默认不允许两个节点的关键值相同 进行中序遍历可以得到递增的有序序列 查找效率 取决与树的高度,最好O(log ...
- Win10安装gcc
使用MinGW安装gcc 1.下载MinGW,地址 https://sourceforge.net/projects/mingw/files/ ,选择Download mingw-get-setup. ...
- Kotlin之内联回调函数
let 定义: let扩展函数的实际上是一个作用域函数,当你需要去定义一个变量在一个特定的作用域范围内,let函数的是一个不错的选择:let函数另一个作用就是可以避免写一些判断null的操作. 翻译: ...
- MySQL之连接查询和子查询
多表连接的基本语法 多表连接,就是将几张表拼接为一张表,然后进行查询 select 字段1, 字段2, ... from 表1 {inner|lift|right} join 表2 on 连接条件; ...