【省选模拟】—猎人杀(概率dp)

加特林轮盘赌差别不大(虽然我没做过……)

考场上想了一个利用树状图转移的 n 3 n^3 做法
但是觉得写不出来就没做…

实际上可以很简单的列出 d p dp
f [ i ] [ j ] f[i][j] 表示剩 i i 个人,第 j j 个人活下来的概率
f [ i ] [ j ] = ( f [ i 1 ] [ j 1 ] + f [ i ] [ j k ] ) / 2 f[i][j]=(f[i-1][j-1]+f[i][j-k])/2
发现这是带环的
而且多个环相互独立的
手动消元就可以了

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
#define int long long
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob)?EOF:*ib++;
}
#define gc getchar
const int mod=1e9+7,inv=5e8+4;
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
inline int add(int a,int b){
	return a+b>=mod?a+b-mod:a+b;
}
inline int mul(int a,int b){
	return a*b>=mod?a*b%mod:a*b;
}
inline int dec(int a,int b){
	return a>=b?a-b:a-b+mod;
}
inline int ksm(int a,int b,int res=1){
	for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;
	return res;
}
const int N=2005;
struct data{
	int x,y;
	data(int _x=0,int _y=0):x(_x),y(_y){}
	friend inline data operator +(const data &a,const data &b){
		return data(a.x+b.x,a.y+b.y);
	}
	friend inline data operator+(const data&a,const int&b){
		return a+data(0,b);
	}
	friend inline data operator *(const data &a,int b){
		return data(mul(a.x,b),mul(a.y,b));
	}
}g[N];
bool vis[N];
int f[N][N],k,idx[N];
inline int pre(int i,int j){
	return j==k?i:(j>k?j-k:j-k+i);
}
inline int nxt(int i,int j){
	return j+k<=i?j+k:j+k-i;
}
inline void calc(int n,int m){
	vis[m]=1,idx[1]=m;
	if(m!=k)g[1]=data(inv,mul(inv,f[n-1][pre(n,m)]));
	else g[1]=data(inv,0);
	int p=nxt(n,m),pr=m,tim=2,x0;
	while(!vis[p]){
		idx[tim]=p,vis[p]=1;
		if(p!=k)g[tim]=(g[tim-1]+f[n-1][pr])*inv;
		else g[tim]=g[tim-1]*inv;
		pr=p,p=nxt(n,p),++tim;
	}
	--tim;
	x0=mul(g[tim].y,ksm(dec(1,g[tim].x),mod-2));
	for(int i=1;i<=tim;i++)f[n][idx[i]]=add(mul(g[i].x,x0),g[i].y);
}
int n,K;
signed main(){
	n=read(),K=read();
	f[1][1]=1;
	for(int i=2;i<=n;i++){
		memset(vis,0,sizeof(vis));
		k=(K%i==0)?i:(K%i);
		for(int j=1;j<=i;j++)if(!vis[j])calc(i,j);
	}
	cout<<f[n][1];
}

猜你喜欢

转载自blog.csdn.net/qq_42555009/article/details/89047261
今日推荐