[SDOI2017]硬币游戏

考虑令\(p_i\)表示第\(i\)个人赢的概率,那么显然我们可以得到。

\[p_i+\sum_{j=1}^np_j(\sum_{k=1}^{m-[i==j]}[prefix(i,k)=suffix(j,k)]\frac{1}{2^{m-k}}) = \frac{1}{2^m} \]

然后高斯消元即可。

/*
  mail: mleautomaton@foxmail.com
  author: MLEAutoMaton
  This Code is made by MLEAutoMaton
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define ll long long
#define re register
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
inline int gi(){
	int f=1,sum=0;char ch=getchar();
	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return f*sum;
}
const int N=310;
int n,m;
char s[N];
typedef unsigned long long ull;
const ull base=19260817;
ull Hash[N][N],pw[N];
double a[N][N],ans[N],fac[N];
void init(){
	pw[0]=1;for(int i=1;i<=m;i++)pw[i]=pw[i-1]*base;
	fac[0]=1;for(int i=1;i<=m;i++)fac[i]=fac[i-1]*1./2;
}
void Gauss(int n){
	for(int i=1;i<=n;i++){
		int id=i;
		for(int j=i+1;j<=n;j++)
			if(fabs(a[id][i])<fabs(a[j][i]))id=j;
		if(id!=i)swap(a[id],a[i]);
		for(int j=i+1;j<=n;j++){
			double delta=a[j][i]/a[i][i];
			for(int k=i;k<=n+1;k++)
				a[j][k]-=delta*a[i][k];
		}
	}
	for(int i=n;i;i--){
		ans[i]=a[i][n+1]/a[i][i];
		for(int j=1;j<i;j++)
			a[j][n+1]-=a[j][i]*ans[i];
	}
}
int main(){
#ifndef ONLINE_JUDGE
	freopen("in.in","r",stdin);
#endif
	n=gi();m=gi();init();
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		for(int j=1;j<=m;j++)
			Hash[i][j]=Hash[i][j-1]*base+s[j];
	}
	for(int i=1;i<=n;i++)a[i][n+1]=fac[m],a[i][i]=1;
	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++)
			for(int k=1;k<=m-(i==j);k++)
				if(Hash[i][k]==Hash[j][m]-Hash[j][m-k]*pw[k])a[i][j]+=fac[m-k];
	Gauss(n+1);
	for(int i=1;i<=n;i++)printf("%.8lf\n",ans[i]);
	return 0;
}
posted @ 2019-08-27 22:30  QwQGJH  阅读(116)  评论(0编辑  收藏  举报