51Nod1453 抽彩球

Problem

一个袋子中有n个彩球,他们用k种不同的颜色染色。颜色被从1到k编号。同一种颜色的球看成是一样的。现在从袋中一个一个的拿出球来,直到拿完所有的球。对于所有颜色为i (1<=i<=k-1)的球,他的最后一个球总是在编号比他大的球拿完之前拿完,问这样情况有多少种。

样例解释:这个样例中有2个1号颜色的球,2个2号颜色的球,1个3号颜色的球。三种方案是:
1 2 1 2 3
1 1 2 2 3
2 1 1 2 3

Solution

我们先每种颜色各取出来一个,然后按顺序摆放,假设这就是最后一个球,然后按顺序摆其他球。

比如我要摆i号球,i号球一共有a[i]个,i号球的最后一个球,前面已经有sum[i-1]个球,那我们在摆第1个i号球时,有sum[i-1]+1种选择,第2个有sum[i-1]+2种,第a[i]-1个有sum[i-1]+a[i]-1,即sum[i]-1种,最后要除以(a[i]-1)!,因为没有顺序。就是说(sum[i-1]+1)(sum[i-1]+2)...(sum[i-1]+a[i]-1)/(a[i]-1)!,即C[sum[i]-1][a[i]-1]种可能,相乘即可,可以用费马小定理来处理除法。

Code

#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll mod=1000000007;
ll k,a[1020],ans=1,f1[1020]={1,1},f2[1020]={1,1};
ll speed(ll a,ll b,ll p){
	ll cur=a,ans=1;
	while(b){
		if(b&1) ans=ans*cur%p;
		cur=cur*cur%p;
		b>>=1;
	}
	return ans%p;
}
int main(){
	for(int i=1;i<=1000;i++){
		f1[i]=f1[i-1]*i%mod;
		f2[i]=f2[i-1]*speed(i,mod-2,mod)%mod;
	}
	scanf("%lld",&k);
	for(int i=1;i<=k;i++){
		scanf("%lld",&a[i]);
		a[i]+=a[i-1];
	}
	for(int i=1;i<=k;i++){
		int sum=a[i]-1,part=a[i]-a[i-1]-1;
		ans=ans*f1[sum]%mod*f2[part]%mod*f2[sum-part]%mod;
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2020-04-21 00:04  CCWUCMCTS  阅读(118)  评论(0编辑  收藏  举报