传送门
简单组合数学想优化想了半天啊233。
我们只需考虑翻开n张A,b张B,c张C且最后一张为A的选法数。
显然还剩下
m
+
k
−
b
−
c
m+k-b-c
m+k−b−c张牌没有选。
这样的话无论前
n
+
b
+
c
n+b+c
n+b+c张牌怎么选,方案数会乘上一个
3
m
+
k
−
b
−
c
3^{m+k-b-c}
3m+k−b−c。
继续讨论。
我们应该从前
n
+
b
+
c
−
1
n+b+c-1
n+b+c−1中选出
n
−
1
n-1
n−1个A(因为最后一个一定是A)。
剩下的要么是B要么是C。
我们不妨令b+c=i。
那么有:
a
n
s
=
∑
(
i
=
0
m
+
k
3
m
+
k
−
i
(
n
+
i
−
1
n
−
1
)
∑
[
b
+
c
=
i
]
,
b
≤
m
,
c
≤
k
)
(
i
b
)
ans=\sum( _{i=0} ^{m+k} 3^{m+k-i}\binom {n+i-1} {n-1}\sum _{[b+c=i],b\le m,c\le k}) \binom {i} {b}
ans=∑(i=0m+k3m+k−i(n−1n+i−1)∑[b+c=i],b≤m,c≤k)(bi)
然后发现前面的一坨都不能优化。
只能在最后一部分做文章。
所以如何优化?
发现我们从i变到i+1的过程相当于杨辉三角向下移动一行的情况。
因此讨论一下边界分情况转移就行了。
代码:
#include<bits/stdc++.h>
#define N 300005
#define mod 1000000007
#define ll long long
using namespace std;
ll up,n,m,k;
ll ans=0,fac[N*3],ifac[N*3],mul[N*3];
inline ll calc(int a,int b){return fac[a]*ifac[b]%mod*ifac[a-b]%mod;}
inline ll ksm(ll x,int p){
ll ret=1;
while(p){
if(p&1)ret=ret*x%mod;
x=x*x%mod,p>>=1;
}
return ret;
}
int main(){
cin>>n>>m>>k,up=n+m+k,fac[0]=mul[0]=ifac[1]=ifac[0]=1;
for(ll i=2;i<=up;++i)ifac[i]=(mod-mod/i)*ifac[mod%i]%mod;
for(ll i=1;i<=up;++i)mul[i]=mul[i-1]*3%mod,(ifac[i]*=ifac[i-1])%=mod,fac[i]=fac[i-1]*i%mod;
if(m<k)m^=k,k^=m,m^=k;
for(ll i=0,j=1;i<=m+k;++i){
(ans+=calc(n-1+i,n-1)*mul[m+k-i]%mod*j%mod)%=mod;
if(i<k)(j<<=1)%=mod;
else if(i>=m)(j+=j-calc(i,k)-calc(i,i-m))%=mod;
else (j+=j-calc(i,k))%=mod;
}
cout<<(ans+mod)%mod;
return 0;
}