【LOJ2513】「BJOI2018」治疗之雨

题意

你现在有 \(m+1\) 个数:第一个为 \(p\) ,最小值为 \(0\) ,最大值为 \(n\) ;剩下 \(m\) 个都是无穷,没有最小值或最大值。你可以进行任意多轮操作,每轮操作如下:

在不为最大值的数中等概率随机选择一个(如果没有则不操作),把它加一;

进行 \(k\) 次这个步骤:在不为最小值的数中等概率随机选择一个(如果没有则不操作),把它减一。

现在问期望进行多少轮操作以后第一个数会变为最小值 \(0\)

\(1 \leq p \leq n \leq 1500\)\(0 \leq m, k \leq 10^9\)

Solution

显然我们只用考虑第一个数的变化。

\(P_x\) 表示一次操作 \(-x\) 概率,即 \(k\) 次中选出 \(x\) 次,剩余 \(k-x\) 次分配到其他 \(m\) 个数。

\[P_x=\frac{\binom{k}{x}m^{k-x}}{(m+1)^k} \]

\(Q_{x,y}\) 表示一次操作从 \(x\) 变到 \(y\) 的概率,不难推出

\[Q_{x,y}=\begin{equation} \left\{ \begin{array}{lr} 0 & x=n 且 y=n+1 &\\ P_{x-y} & x=n\\ \frac{1}{m+1}P_0 & y=x+1\\ \frac{m}{m+1}P_{x-y}+\frac{1}{m+1}P_{x-y+1} & \text{otherwise} \end{array} \right. \end{equation} \]

\(f(i)\) 表示从 \(i\) 变到 \(0\) 的期望操作数。

\[\begin{align} & f(i)=1+\sum_{j=1}^{i+1} Q_{i,j}f(j) & (1\le i<n) \\ & f(n)=1+\sum_{j=1}^nQ_{n,j}f(j) \end{align} \]

我们可以 \(n^2\) 消元上述式子。将 \((1)\) 变形可得

\[\begin{align} f(i+1)=\frac{f(i)-\sum_{j=1}^iQ_{i,j}f(j)-1}{Q_{i,i+1}} \end{align} \]

可以利用 \((3),(4)\) 得到 \(f(n)\) 关于 \(f(1)\) 的两个方程,解出 \(f(1)\) 后带入即可。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int Mod=1e9+7,N=1505;
inline int mul(int x, int y) { return 1ll*x*y%Mod; }
inline int po(int x, int y)
{
	int r=1;
	while(y)
	{
		if(y&1) r=mul(r,x);
		x=mul(x,x), y>>=1;
	}
	return r;
}
int f[N],x[N],y[N],fac[N],inv[N],n,p,m,k,iv;
inline int calcp(int x, int y)
{ 
	if(x==n&&y==n+1) return 0;
	if(x==n) return f[x-y];
	if(y==x+1) return mul(iv,f[0]);
	return (mul(mul(m,iv),f[x-y])+mul(f[x-y+1],iv))%Mod;
}
int main()
{
	int T; scanf("%d",&T);
	fac[0]=inv[0]=1;
	for(int i=1;i<=1500;++i) fac[i]=mul(i,fac[i-1]);
	inv[1500]=po(fac[1500],Mod-2);
	for(int i=1499;i;--i) inv[i]=mul(inv[i+1],i+1);
	while(T--)
	{
		scanf("%d%d%d%d",&n,&p,&m,&k);
		if(!k||(!m&&k==1))
		{
			puts("-1");
			continue;
		}
		if(!m)
		{
			int ans=0;
			while(p>0)
			{
				if(p<n) ++p;
				p-=k,++ans;
			}
			printf("%d\n",ans);
			continue;
		}
		int inv0=po(m,Mod-2),inv1=po(po(m+1,k),Mod-2);
		iv=po(m+1,Mod-2);
		for(int i=0,j=1,g=po(m,k),l=min(n,k);i<=l;++i)
		{
			f[i]=mul(mul(mul(j,inv[i]),g),inv1);
			j=mul(j,k-i),g=mul(g,inv0);
		}
		x[1]=1,y[1]=0;
		for(int i=2;i<=n;++i)
		{
			x[i]=x[i-1],y[i]=(Mod+y[i-1]-1)%Mod;
			for(int j=1;j<i;++j)
			{
				int tmp=calcp(i-1,j);
				x[i]=(x[i]+Mod-mul(x[j],tmp))%Mod;
				y[i]=(y[i]+Mod-mul(y[j],tmp))%Mod;
			}
			int tmp=po(calcp(i-1,i),Mod-2);
			x[i]=mul(x[i],tmp),y[i]=mul(y[i],tmp);
		}
		int nx=0,ny=1;
		for(int i=1;i<=n;++i)
		{
			int tmp=calcp(n,i);
			nx=(nx+mul(x[i],tmp))%Mod;
			ny=(ny+mul(y[i],tmp))%Mod;
		}
		int tmp=mul((ny-y[n]+Mod)%Mod,po((x[n]-nx+Mod)%Mod,Mod-2));
		printf("%d\n",(mul(tmp,x[p])+y[p])%Mod);
		memset(f,0,sizeof(int)*(min(n,k)+1));
	}
}
posted @ 2019-06-13 19:59  x_faraway_x  阅读(304)  评论(0编辑  收藏  举报