51Nod 1453 抽彩球

 

题目来源: CodeForces
基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
 收藏
 关注

一个袋子中有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

Input
单组测试数据。
第一行给出一个整数k(1 ≤ k ≤ 1000),表示球的种类。
接下来k行,每行一个整数ci,表示第i种颜色的球有ci个(1 ≤ ci ≤ 1000)。
球的总数目不超过1000。
Output
输出总数对1,000,000,007的模即可。
Input示例
3
2
2
1
Output示例
3

正着放球有许多限制 我们很难求解
我们可以考虑反着放
题目要求 你想放最后一个种类为2的球 那么你种类为1的球一定已经全部放在这最后一个种类为2的球的前面位置 (看着样例理解)
对于第i个 球我们一定会在最后一个空位置放一个 然后其他的可以在前面的空位置随便放
就是 C(空位置数量,c[i]-1)

对于第i-1种球 我们要先在最后一个空位置放一个 其他再往前放
.
.
.

可以发现
这就是求一个组合数C(n,m) 由于 n,m 在10^6左右
我们可以用Lucas定理
Lucas定理 C(n,m)%p(p为素数)
C(n,m)与C(a[n],b[n])*C(a[n-1],b[n-1])*C(a[n-2],b[-2])*....*C(a[0],b[0])模p同余
a,b 是n,m在p进制下的数
有的推公式: (C(n%p,m%p,p)*Lcs(n/p,m/p,p))%p;
关键是求 C(n%p,m%p,p) 递归会很慢 for的话会爆掉
这里用一个定理:a/b%p <--> a*x%p  x为b在b%p下的逆元
再来一个定理:x=b^(p-2)   x为b在%p下的逆元  p为素数
然后预处理一下阶乘就ok了 
 
 1 #include <cctype>
 2 #include <cstdio>
 3 
 4 typedef long long LL;
 5 
 6 const int mod=1e9+7;
 7 const int MAXN=1000010;
 8 
 9 int n,sum;
10 
11 int c[MAXN];
12 
13 LL fact[MAXN];
14 
15 inline void read(int&x) {
16     int f=1;register char c=getchar();
17     for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar());
18     for(;isdigit(c);x=x*10+c-48,c=getchar());
19     x=x*f;
20 }
21 
22 inline LL quick_pow(LL a,LL k) {
23     LL ret=1;
24     while(k) {
25         if(k&1) ret=(ret*a)%mod;
26         k>>=1;
27         a=(a*a)%mod;
28     }
29     return ret%mod;
30 }
31 
32 inline LL C(int a,int b) {
33     return fact[a]*quick_pow(fact[b]*fact[a-b]%mod,mod-2)%mod;
34 }
35 
36 inline void Factorial() {
37     fact[0]=1;
38     for(int i=1;i<=MAXN;++i)
39       fact[i]=(fact[i-1]*i)%mod;
40 }
41 
42 int hh() {
43     Factorial();
44     read(n);
45     for(int i=1;i<=n;++i) read(c[i]),sum+=c[i];
46     LL ans=1;
47     for(int i=n;i;--i) {
48         ans=(ans*C(sum-1,c[i]-1))%mod;
49         sum-=c[i];
50     }
51     printf("%lld\n",ans);
52     return 0;
53 }
54 
55 int sb=hh();
56 int main(int argc,char**argv) {;}
代码

 

 
posted @ 2017-09-21 17:00  拿叉插猹哈  阅读(103)  评论(0编辑  收藏  举报