2018.09.19 atcoder Card Game for Three(组合数学)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/82778499

传送门
简单组合数学想优化想了半天啊233。
我们只需考虑翻开n张A,b张B,c张C且最后一张为A的选法数。
显然还剩下 m + k b c m+k-b-c 张牌没有选。
这样的话无论前 n + b + c n+b+c 张牌怎么选,方案数会乘上一个 3 m + k b c 3^{m+k-b-c}

继续讨论。

我们应该从前 n + b + c 1 n+b+c-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}
然后发现前面的一坨都不能优化。
只能在最后一部分做文章。
所以如何优化?
发现我们从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;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/82778499
今日推荐