题解:P3706 [SDOI2017] 硬币游戏&P6125 [JSOI2009] 有趣的游戏

P3706 P6125

首先发现两道题是相同的,但是 P3706 的数据更大,P6125 的字符集更大,同时每种字符的概率不同,接下来我们按 P6125 的题面和 P3706 的数据来叙述。

考虑设 \(f_{i,j}\)\(j\) 次随机后恰好以第 \(i\) 个串结束的概率,其对于每个串的生成函数为 \(F_i(x)\)。设 \(g_i\)\(i\) 次随机后仍未结束的概率,其生成函数为 \(G(x)\)。发现这个东西很像 P4548 [CTSC2006] 歌唱王国,因而我们可以按类似的做法(题解:P4548 [CTSC2006] 歌唱王国)来做。

\(P_i(l,r)\) 表示取到第 \(i\) 个串的 \([l,r]\) 的概率,即 \(\prod\frac pq\)\(n\) 为串的数量,\(L\) 为每个串的长度,\(m\) 为字符集的大小,则对于每个串 \(i\) 都有:

\[G(x)P_i(1,L)x^L=\sum_{j=1}^n\sum_{k=1}^L[s_i[1,k]=s_j[L-k+1,L]]F_j(x)x^{L-k}P_i(k+1,L) \]

即我们在一个未结束状态后拼一整个 \(s_i\) 后必定会结束,但也有可能提前结束,如果提前结束在第 \(j\) 个串,则 \(j\) 的后拼的部分(一个后缀,假设长度为 \(k\))必然和 \(i\) 的前缀相同,即 \(s_i[1,k]=s_j[l-k+1,l]\),于是我们在后面拼上只是 \(s_i[k+1,l]\),所以要乘上 \(P_i(k+1,l)\)。又因为 \(i\) 的答案就是 \(F_i(1)=\sum_{j=0}^\infty f_{i,j}\),所以我们带入 \(x=1\),有:

\[G(1)P_i(1,L)=\sum_{j=1}^n\sum_{k=1}^L[s_i[1,k]=s_j[L-k+1,L]]F_j(1)P_i(k+1,L) \]

\[G(1)=\sum_{j=1}^n\sum_{k=1}^L\frac{[s_i[1,k]=s_j[L-k+1,L]]}{P_i(1,k)}F_j(1) \]

于是我们可以通过哈希或 AC 自动机 \(O(n^3)\) 地列出关于 \(F_i(1)\)\(G(1)\)\(n+1\) 个变量的 \(n\) 个方程,再加上 \(\sum_{i=1}^nF_i(1)=1\) (因为有无限次随机,必定会结束)这个方程,共 \(n+1\) 个方程,高斯消元即可。

但是对于 P6125 需要特判一下 \(p=0\) 的情况,将这种情况下的 \(\frac pq\) 设为一个 \(10^{-7}\) 之类的小数,否则高斯消元会消到 \(0\) 然后寄掉。而且可能所有的串都不可能被摇出来,此时 \(\sum_{i=1}^nF_i(1)=0\) 也需要特判一下,可以对不能被摇出来的串直接输出 \(0\)

参考资料:题解 P3706 【[SDOI2017]硬币游戏】题解 P6125【[JSOI2009]有趣的游戏】

Code of P6125(P3706简单改一下就行):

#include<iostream>
#include<cmath>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,l,r) for(int i=(l);i>=(r);i--)
using namespace std;
const int maxn=310,mod=1e9+7;
typedef long long ll;
typedef long double ld;
const ld eps=1e-9;
ld a[maxn][maxn],ap[maxn][maxn],ac[30];
bool az[maxn],as[30];
int bas;
ll pw[maxn],pre[maxn][maxn],suf[maxn][maxn];
char s[maxn];
inline void gause(int n){
	rep(v1,1,n){
		int p=v1;
		rep(v2,v1+1,n)if(abs(a[v2][v1])>abs(a[p][v1]))p=v2;
		rep(v2,1,n+1)swap(a[v1][v2],a[p][v2]);
		ld t=a[v1][v1];
		rep(v2,1,n+1)a[v1][v2]/=t;
		rep(v2,1,n)if(v2!=v1){
			t=a[v2][v1];
			rep(v3,1,n+1)a[v2][v3]-=t*a[v1][v3];
		}
	}
}
int main(){
//	freopen("P6125_5.in","r",stdin);
	int in,il,im;
	cin>>in>>il>>im;
	bas=im+1;
	rep(v1,1,im){
		int ip,iq;
		scanf("%d %d",&ip,&iq);
		if(ip)ac[v1-1]=ld(ip)/iq;
		else ac[v1-1]=0.0000001,as[v1-1]=true;
	}
	pw[0]=1;
	rep(v1,1,il)pw[v1]=pw[v1-1]*bas%mod;
	rep(v1,1,in){
		scanf("%s",s+1);
		ap[v1][0]=1;
		rep(v2,1,il)ap[v1][v2]=ap[v1][v2-1]*ac[s[v2]-'A'],az[v1]|=as[s[v2]-'A'];
		rep(v2,1,il)pre[v1][v2]=(pre[v1][v2-1]*bas+s[v2]-'A'+1)%mod;
		per(v2,il,1)suf[v1][v2]=((s[v2]-'A'+1)*pw[il-v2]+suf[v1][v2+1])%mod;
	}
	rep(v1,1,in){
		rep(v2,1,in)rep(v3,1,il){
			a[v1][v2]+=(pre[v1][v3]==suf[v2][il-v3+1])/ap[v1][v3];
		}
		a[v1][in+1]=-1;
	}
	rep(v1,1,in)a[in+1][v1]=1;
	a[in+1][in+2]=1;
	gause(in+1);
	rep(v1,1,in)printf("%.2LF\n",az[v1]?0:a[v1][in+2]);
	return 0;
}
posted @ 2025-03-08 11:00  FugiPig  阅读(32)  评论(0)    收藏  举报