题解 agc053F 【ESPers】

问题陈述

\(2N+1\)玩家将玩一个投票游戏.每个玩家对两个选项中的一个进行投票,选择最终获得更多票数的选项的玩家将获胜.投票的过程如下:

1.如果每个人都已经投票,则投票结束.否则,继续步骤2.

2.在没有投票的选手中随机选出一名选手,他/她投一票.然后,返回步骤1.

其中\(K\)名玩家是ESPers,他们在投票时可以知道每个选项的投票数.因此,所有玩家将以如下方式投票:

如果该玩家是一个ESPer,他/她将投票给在目前获得更多的票数的选项.如果两个选项的票数相同,他/她将随机投票给一个选项.

如果该玩家一个不是ESPer,他/她将投票给随机一个选项.

X是这个游戏的玩家,同时也是一个ESPer.求X获胜的概率,答案模\((10^9+7)\).

约束条件

\(1\le N\le 2\times 10^6\)

\(1\le K\le 2N+1\)

题解(计数)

其实是翻译题解,不会让其起到商业作用,应该不会有版权问题吧.

\(p\)为X投票后某一时刻两个选项拥有相同票数的概率.那么,答案是\(1−\frac{p}{2}\),接下来我们要算出\(p\).

首先,让我们放置\(K\)个ESPers和\(2N+1−K\)个非ESPers进一个序列,并确定每个非ESPers是投票给当时票数较多的选项还是票数较少的选项.有\(\binom{2N+1}{K}×2^{2N+1-K}\)个状态.我们要求当两个选项的投票数相同时X已经投票的概率之和.

让我们给让每个状态对应一个长度为\(2N+1\)的序列,其由\(1\)\(-1\)组成,对于每个\(1≤i≤2N+1\),如果第\(i\)个玩家对票数较多的选项投了票,则序列的第\(i\)项为\(1\),否则为\(-1\).

使用非负整数\(x\)\(y\),我们可以将此序列唯一地表示为:

\[S_0,-1,S_1,-1,\dots,S_x,1,S_{x+1},1,\dots,S_{x+y} \]

其中每个\(Si\)是一个由\(1\)\(-1\)组成的序列,其每个前缀和都是非负的,整个和是\(0\).注意,\(S_i\)可能是空的.

下面,我们将固定\(x\)\(y\),分别算出选择ESPers的相应方法的数目,当两个选项最后一次的投票数相同X已经投票的概率,以及相应的序列\(S_0,\dots,S_{x+y}\)的数目.因为序列的长度是\(2N+1\),所以\(x+y\)是奇数.

首先,\(S_0,\dots,S_{x+y}\)的总长度为\(2N+1−x−y\). 它们的一半元素是\(1\),所以整个序列包含\(\frac{2N+1−x+y}{2}\)\(1\).因此,有\(\binom{\frac{2N+1−x+y}{2}}{K}\)种选择ESPers的相应方法.

接下来,考虑两个选项最后一次获得相同投票数的时间节点.如果\(x\)是偶数,\(S_x\)的结束位置是最后一次投票,如果x是奇数,则是\(S_{x-1}\)的结束位置.从\(S_0\)\(S_x\)的平均\(1\)的个数是\(\frac{(x+1)(2N+1−x−y)}{2(x+y+1)}\),从\(S_0\)\(S_{x-1}\)的平均\(1\)的个数是\(\frac{x(2N+1−x−y)}{2(x+y+1)}\).因此,当两个选项最后一次拥有相同票数时,\(X\)已经投票的概率为:

如果\(x\)是偶数\(\frac{(x+1)(2N+1−x−y)}{(x+y+1)(2N+1−x+y)}\),如果\(x\)是奇数\(\frac{x(2N+1−x−y)}{(x+y+1)(2N+1−x+y)}\).

最后,计算相应的\(S\).这等于长度为\(2N+1\),形式为\(S_0,1,S_1,\dots,1,S_{x+y}\)的序列数,因此计数为\(\binom{2N+1}{\frac{2N+1−x−y}{2}}-\binom{2N+1}{\frac{2N−1−x−y}{2}}\).

现在,我们可以找到偶数\(x\)的答案:

\(\binom{\frac{2N+1-x+y}{2}}{K}\times\frac{(x+1)(2N+1-x-y)}{(x+y+1)(2N+1-x+y)}\times(\binom{2N+1}{\frac{2N+1-x-y}{2}}-\binom{2N+1}{\frac{2N−1−x−y}{2}})\)

对于奇数\(x\):

\(\binom{\frac{2N+1−x+y}{2}}{K}\times \frac{x(2N+1-x−y)}{(x+y+1)(2N+1-x+y)}×(\binom{2N+1}{\frac{2N+1-x-y}{2}}-\binom{2N+1}{\frac{2N−1-x−y}{2}}\)

现在,我们有了一个\(O(N^2)\)的解.

考虑怎么更快地计算偶数\(x\)的答案(奇数\(x\)的和可以类似地计算,所以我们在这里省略它).

如果我们固定\(x+y=2k+1(0\le k\le N)\),上述公式只有以下部分取决于\(x\):

\(\binom{\frac{2N+1−x+y}{2}}{K}\times \frac{x+1}{2N+1−x+y}=\frac {x+1}{2K}\times \binom{N+k−x}{K-1}\)

因此,我们只需要算出\(\sum^{k}_{a=0}(2a+1)\binom{N+k-2a}{K-1}\),我们可以用前缀和来计算它.

因此,该问题可以在线性时间内求解.

#include<algorithm>
#include<iostream>
#include<complex>
#include<cstdlib>
#include<cstring>
#include<utility>
#include<bitset>
#include<cstdio>
#include<string>
#include<time.h>
#include<vector>
#include<cmath>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
const int N=4e6+5,M=1e9+7;
int l[N],c[N],y[N],q[N];
int ksm(int a,int b)
{
	int c=1;
	while(b)
	{
		if(b&1)
			c=1ll*c*a%M;
		a=1ll*a*a%M;
		b>>=1;
	}
	return c;
}
int C(int a,int b)
{
	if(b<0||a<b)
		return 0;
	return 1ll*c[a]*y[b]%M*y[a-b]%M;
}
int main()
{
	int n,k,a=0;
	scanf("%d%d",&n,&k);
	c[0]=1;
	for(int i=0;i<=(n<<1);i++)
		c[i+1]=1ll*c[i]*(i+1)%M;
	y[(n<<1)|1]=ksm(c[(n<<1)|1],M-2);
	for(int i=(n<<1);~i;i--)
		y[i]=1ll*y[i+1]*(i+1)%M;
	for(int i=0;i<=(n<<1);i++)
		l[i+1]=1ll*y[i+1]*c[i]%M;
	q[0]=C(0,k-1),q[1]=C(1,k-1);
	for(int i=0;i<(n<<1);i++)
		q[i+2]=(q[i]+C(i+2,k-1))%M;
	for(int i=0,s=0;i<n;i++)
	{
		s=(s+C(n+i,k-1)+1ll*C(n-i-1,k-1)*((i<<1)|1)+(((n+i>1?q[n+i-2]:0)-(n>i+1?q[n-i-2]:0))<<1))%M;
		a=(a+1ll*(n-i)*l[i+1]%M*(C((n<<1)|1,n-i)-C((n<<1)|1,n-i-1))%M*s)%M;
	}
	printf("%lld",(1+M-1ll*a*l[k]%M*ksm(1ll*C((n<<1)|1,k)*ksm(2,(n<<1)-k+3)%M,M-2)%M)%M);
}
posted @ 2021-07-13 21:36  Manners  阅读(66)  评论(0编辑  收藏  举报