概率生成函数学习笔记

[CTSC2006]歌唱王国

这个更详细的全部解题过程详见 M_sea 的题解,他写的很好。

我就讲一下为什么 \(G(x)(\dfrac xn)^m=\sum\limits_{i=1}^m a_i (\dfrac xn)^{m-i} F(x)\) 成立。

左式意义是对于当前的一个还未结束的串,我们在其后面加上一个整串的概率。

易知此时已经结束,则我们枚举结束时间,要求这个时间结束后再填完整串,故这个后缀必须是一个 border

#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int base=19260817;
const int mod=1e9+7;
const int MOD=1e4;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
int n,T,m,a[maxn],hs[maxn],pw[maxn],res;
inline int calc(int l,int r){return (hs[r]-1ll*hs[l-1]*pw[r-l+1]%mod+mod)%mod;}
inline void solve(){
	m=read();res=0;
	for(int i=1;i<=m;i++){
		a[i]=read();
		hs[i]=(a[i]+1ll*hs[i-1]*base)%mod;
	}
	for(int i=1,w=1;i<=m;i++){
		w=w*n%MOD;
		if(calc(1,i)==calc(m-i+1,m))res=(res+w)%MOD;
	}int tmp=1000;
	for(int i=1;i<=4;i++){
		printf("%d",res/tmp);
		res%=tmp;tmp/=10;
	}puts("");
}
int main(){
	n=read(),T=read();
	pw[0]=1;
	for(int i=1;i<=100000;i++)
		pw[i]=1ll*pw[i-1]*base%mod;
	while(T--)solve();
	return 0;
}

[SDOI2017]硬币游戏

相似的做法,核心还是那个式子,只是变成了多元,于是考虑高斯消元即可。

#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int base=131;
const int mod=1e9+7;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
const int N=305;
int n,m,hs[N][N],pw[N];char c[N][N];
double a[N][N],p2[N];
inline int calc(int id,int l,int r){return (hs[id][r]-1ll*hs[id][l-1]*pw[r-l+1]%mod+mod)%mod;}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		scanf("%s",c[i]+1);
		for(int j=1;j<=m;j++)
			hs[i][j]=(1ll*hs[i][j-1]*base+c[i][j]-'A'+1)%mod;
	}pw[0]=p2[0]=1;a[n+1][n+2]=1;
	for(int i=1;i<=m;i++)
		pw[i]=1ll*pw[i-1]*base%mod,p2[i]=p2[i-1]/2.0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			for(int k=1;k<=m;k++)
				if(calc(i,1,k)==calc(j,m-k+1,m))a[i][j]+=p2[m-k];
	for(int i=1;i<=n;i++)a[i][n+1]=-p2[m],a[n+1][i]=1;
	for(int i=1;i<=n+1;i++){
		int pos=i;
		for(int j=i+1;j<=n+1;j++)
			if(fabs(a[pos][i])<fabs(a[j][i]))pos=j;
		if(pos^i)for(int j=1;j<=n+2;j++)
			swap(a[i][j],a[pos][j]);
		for(int j=1;j<=n+1;j++){
			if(i==j)continue;
			double k=a[j][i]/a[i][i];
			for(int p=i;p<=n+2;p++)
				a[j][p]-=a[i][p]*k;
		}
	}
	for(int i=1;i<=n;i++)
		printf("%.8lf\n",a[i][n+2]/a[i][i]);
	return 0;
}
posted @ 2022-04-09 15:59  syzf2222  阅读(46)  评论(0编辑  收藏  举报