[SDOI2017] 硬币游戏

\(\text{Problem}:\)[SDOI2017] 硬币游戏

\(\text{Solution}:\)

如果 \(n=1\) 并且求期望时间就是 [CTSC2006] 歌唱王国,而本题做法也是类似的。

\(f_{i,j}\) 表示随机了 \(j\) 次出现了序列 \(s_{i}\) 的概率,\(g_{i}\) 表示随机了 \(i\) 次还没有出现任何一个序列的概率。设 \(F_{i}(x)\) 表示序列 \(f_{i}\) 的生成函数,\(G(x)\) 表示序列 \(g\) 的生成函数,有:

\[xG(x)+1=G(x)+\sum\limits_{i=1}^{n}F_{i}(x) \]

考虑 \(\text{border}\) 的存在,在补上字符串 \(s_{i}\) 时可能已经出现了字符串 \(s_{j}\),故有:

\[G(x)\frac{x^{m}}{2^{m}}=\sum\limits_{j=1}^{n}\sum\limits_{k=1}^{m}[s_{i}[1:k]=s_{j}[m-k+1,m]]F_{j}(x)(\frac{x}{2})^{m-k} \]

要求的是 \(F_{i}(1)\)。将 \(x=1\) 代入,有:

\[G(1)=\sum\limits_{j=1}^{n}F_{j}(1)\sum\limits_{k=1}^{m}[s_{i}[1:k]=s_{j}[m-k+1,m]]\cdot 2^{k} \]

现在可以列出 \(n\) 条关于 \(n+1\) 个未知数的方程。注意有 \(\sum\limits_{i=1}^{n}F_{i}(1)=1\),故可以高斯消元得解。总时间复杂度 \(O(n^{3})\)

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=310, M1=998244353, B1=137, M2=1e9+9, B2=191;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,m;
int pw1[N],pw2[N];
int hsh1[N][N],hsh2[N][N];
char s[N][N];
double pw[N],a[N][N];
inline pair<int,int> Hash(int id,int x,int y)
{
	int w1=(hsh1[id][y]-1ll*hsh1[id][x-1]*pw1[y-x+1]%M1+M1)%M1;
	int w2=(hsh2[id][y]-1ll*hsh2[id][x-1]*pw2[y-x+1]%M2+M2)%M2;
	return mk(w1,w2);
}
inline void Gauss()
{
	for(ri int i=1;i<=n+1;i++)
	{
		int pos=i;
		for(ri int j=i;j<=n+1;j++) if(fabs(a[pos][j])>fabs(a[i][j])) pos=i;
		swap(a[i],a[pos]);
		for(ri int j=1;j<=n+1;j++)
		{
			if(i==j) continue;
			double w=a[j][i]/a[i][i];
			for(ri int k=i+1;k<=n+2;k++) a[j][k]-=a[i][k]*w;
		}
	}
	for(ri int i=1;i<=n+1;i++) a[i][n+2]/=a[i][i];
}
signed main()
{
	pw1[0]=pw2[0]=1;
	for(ri int i=1;i<N;i++) pw1[i]=1ll*pw1[i-1]*B1%M1, pw2[i]=1ll*pw2[i-1]*B2%M2;
	pw[0]=1;
	for(ri int i=1;i<N;i++) pw[i]=pw[i-1]*2.0;
	n=read(), m=read();
	for(ri int i=1;i<=n;i++)
	{
		scanf("%s",s[i]+1);
		for(ri int j=1;j<=m;j++)
		{
			hsh1[i][j]=(1ll*hsh1[i][j-1]*B1%M1+s[i][j])%M1;
			hsh2[i][j]=(1ll*hsh2[i][j-1]*B2%M2+s[i][j])%M2;
		}
	}
	for(ri int i=1;i<=n;i++)
	{
		for(ri int j=1;j<=n;j++)
		for(ri int k=1;k<=m;k++) if(Hash(i,1,k)==Hash(j,m-k+1,m)) a[i][j]+=pw[k];
		a[i][n+1]=-1.0;
	}
	for(ri int i=1;i<=n;i++) a[n+1][i]=1.0; a[n+1][n+2]=1.0;
	Gauss();
	for(ri int i=1;i<=n;i++) printf("%.10lf\n",a[i][n+2]);
	return 0;
}
posted @ 2021-05-03 20:09  zkdxl  阅读(47)  评论(0编辑  收藏  举报