CF#309-DIV2-C. Kyoya and Colored Balls-组合数学

http://codeforces.com/contest/554/problem/C

题意 可看作 

给m个颜色的气球,每种颜色有一定数量(至少为1)

然后构造 出 第k个颜色的气球后面不存在有比k小的颜色的气球存在。。。的方案数

正向构造毕竟麻烦,最最后一个入手比较简单、

气球总是为sum、第i种颜色气球有a[i]个

最后一个肯定是第K个颜色,因为序列长度固定为sum,所以第k个颜色摆放方案是C(sum-1,a[k]-1);

接下来的第k-1个颜色气球的最后一个一定是放在最接近  最后一个k的位置(否则如果最接近最后一个k的位置放了 比k-1还小的数,就不符合题意了)

所以第k-1个颜色的气球方案数为 C(sum-a[k]-1,a[k-1]-1);

以此类推

。。

因为组合数太大,,,并且给出的模恰好为素数。。所以直接用费马小定理+快速幂就好了。。

 

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;


int tm[1005]; 
const __int64 mod =1000000007;

__int64 fast_m(__int64 a,__int64 b)
{
	__int64 x,ans=1;
	x=a;
	while(b)
	{
		if (b&1)
			ans=(ans*x)%mod;
		x=(x*x)%mod;
		b/=2;
	}
	return ans;
}
__int64 n;

__int64 fac[1000010];
__int64 cal(__int64 x,__int64 y)
{ 
	__int64 ans=1; 
	ans*=(fac[x]*fast_m(fac[y]*fac[x-y]%mod,mod-2))%mod;  
	
	//(a/b)%mod,等价于(a*b^(mod-2))%mod  mod必须为素数
	return ans;
}
int main()
{
	
	__int64 i;
	fac[0]=1;
	   for(  i=1;i<=1000000;i++)  
		   fac[i]=fac[i-1]*i%mod; 
	   
	   scanf("%I64d",&n); 
	   __int64 sum=0;
	   
	   for(i=1;i<=n;i++)
	   {
		   scanf("%I64d",&tm[i]);
		   sum+=tm[i];
	   }
	   
	   __int64 ans=1;

	   for(i=n;i>=1;i--)
	   {
		   ans*=cal(sum-1,tm[i]-1);
		   ans%=mod;
		   sum-=tm[i];
	   }
	   printf("%I64d\n",ans);
	   
	   
	   return 0;
	   
} 

你可能感兴趣的:(CF#309-DIV2-C. Kyoya and Colored Balls-组合数学)