解析:
在
的强迫下刷了一下这道组合数学
感觉好鬼畜啊这道题。。。
我们发现当每个人手里面的牌确定的时候,每个人出牌的序列是确定的。(废话)
而当我们将三个人的所有出牌按顺序合并成一个序列的时候,我们会发现,每一个序列唯一对应每个人原来手里面牌的情况(仅考虑打出来了的牌)。
那么我们的问题就变成了:
给定
,求有多少个长度为
的由且仅由
构成的序列,满足第
个
之前的
不超过
个,且
不超过
个。
取 是因为 最开始会出一张牌。
那么我们就枚举出现的 和 的总次数,统计将 个 插在这些位置里面的方案数(考虑在最后一个位置放上一个 ,防止方案数算重)。
那么根据乘法原理,每一次枚举的总次数对应的 排列的方案数 将 插在这些缝隙里面的方案数。
那么怎么计算?
首先考虑每次会剩下 张牌,对于当前方案的贡献是 的。
这个可以一边计算一边乘上 (乱搞) 。
那么我们考虑的就是怎么计算当前这么多个 的排列个数。
现在就是帕斯卡三角形上场了。
考虑如下的一个帕斯卡三角形,其中标
号的是我们需要统计的节点。
以二元组
表示
分别取的次数,
那么图中顶上的节点就是
,左下的节点是
,右下的节点就是
从官方题解那里盗的图
发现 处的元素表示的就是选 张 牌, 张 牌的方案数。
显然每一层表示的 是固定的,即同一层的所有方案中,将 插入缝隙中的方案数是一定的。
那么我们考虑直接计算出一整行的总方案数。
首先,第一层的方案数是1。
每次枚举到下一层对答案的影响显然是令方案数翻倍的(不考虑越界的情况)。
因为帕斯卡三角形每一个元素在加法生成的下一行中都会被计算两次。
那么对于越界怎么处理?
发现 每次左边货右边越界会多统计一个帕斯卡三角形的元素,这个多的元素我们可以用组合数 算出来,减去就好了,并且不会影响上面的二倍性质。
于是再乘上一个选择 牌的方案数,这道题就做完了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
cs ll mod=1000000007;
ll fac[1000001]={1,1},inv[1000001]={1,1},ifac[1000001]={1,1};
inline
ll C(int n,int m){
return fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
int n,m,k,maxn;
signed main(){
for(int re i=2;i<=1000000;++i)
fac[i]=fac[i-1]*i%mod,
inv[i]=(mod-mod/i)*inv[mod%i]%mod,
ifac[i]=ifac[i-1]*inv[i]%mod;
scanf("%d%d%d",&n,&m,&k);
--n;
maxn=max(n,m+k);
ll sum=1,ans=1;
for(int re i=1;i<=m+k;++i){
sum=(sum<<1)%mod;
if(i>m)sum=(sum+mod-C(i-1,m))%mod;
if(i>k)sum=(sum+mod-C(i-1,k))%mod;
ans=ans*3%mod;
ans=(ans+C(n+i,i)*sum%mod)%mod;
}
cout<<ans;
return 0;
}