[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;
}
夜畔流离回,暗叹永无殿。
独隐万花翠,空寂亦难迁。
千秋孰能为,明灭常久见。
但得心未碎,踏遍九重天。