ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-09-15 09:05:19  阅读:157  来源: 互联网

标签:概率 hash int P3706 times ull include 高斯消


正题

题目链接: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\)。那么就有

\[p(N)\times 2^{-m}=p(N+A)=p(A)+p(B)\times 2^{-2}+p(B)\times 2^{-1} \]

这样不难发现对于别的串如果它的一些后缀是这个串的前缀那么就会产生一些概率,用字符串\(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;
}

标签:概率,hash,int,P3706,times,ull,include,高斯消
来源: https://www.cnblogs.com/QuantAsk/p/15270666.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有