题目大意
A,B,C三个人玩游戏,最初每个人分别有n,m,k张牌,每张牌上有字母a,b,c之一,但是不知道每张牌具体是什么。由A先操作,每轮操作者翻出自己牌堆顶的一张牌并弃置,下一轮的操作者是该牌上字母对应的人。不能操作的人赢。问有多少种初始牌的情况能使A胜利。答案模1,000,000,007
1≤n,m,K≤300,000
分析
考虑枚举翻牌序列有x个b,有y个c,那么序列长度应该是n+x+y。由于最后一位一定是a,我们可以不管最后一位。
接下来是n-1个a,x个b,y个c任意排列,两个组合数相乘再乘上3的次幂即可。
这样只能拿部分分,考虑枚举i=x+y,那么:
Ans=∑m+ki=0Cn−1n−1+x+y3m+k−x−y∑0≤x≤m,0≤y≤k[x+y=i]Cxi
考虑后面的求和部分。它显然分成三段。形式分别是
∑Mi=0CiM
;
∑ki=0CkM
;
∑ki=tCkM
如果我们知道M=i-1时的总和,要推到M=i时的总和。根据杨辉三角公式,第一种情况直接乘2,第二种是乘2再减掉
Cki−1
,第三种是乘2减掉
Cki−1
和
Ct−1i−1
复杂度是线性的
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=9e5+5,mo=1e9+7;
typedef long long LL;
int n,m,K,ans,Fac[N],Inv[N],p[N];
int C(int n,int m)
{
return (LL)Fac[n]*Inv[m]%mo*Inv[n-m]%mo;
}
int main()
{
p[0]=Fac[0]=Inv[0]=Fac[1]=Inv[1]=1; p[1]=3;
for (int i=2;i<N;i++) Inv[i]=(LL)Inv[mo%i]*(mo-mo/i)%mo;
for (int i=2;i<N;i++)
{
p[i]=p[i-1]*3ll%mo; Fac[i]=(LL)Fac[i-1]*i%mo; Inv[i]=(LL)Inv[i-1]*Inv[i]%mo;
}
scanf("%d%d%d",&n,&m,&K); n--;
if (m<K) swap(m,K);
for (int i=0,j=1;i<=m+K;i++)
{
ans=(ans+(LL)C(n+i,n)*p[m+K-i]%mo*j)%mo;
if (i<K) j=j*2%mo;
else if (i>=m) j=(j*2ll-C(i,K)-C(i,i-m))%mo;
else j=(j*2ll-C(i,K))%mo;
}
if (ans<0) ans+=mo;
printf("%d\n",ans);
return 0;
}