zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    52     return 0;
    53 }
    54 
    55 int sb=hh();
    56 int main(int argc,char**argv) {;}
    代码
    
    
    
     
  • 相关阅读:
    jchdl
    jchdl
    UVa 11134 (区间上的贪心) Fabled Rooks
    UVa (二分) 11627 Slalom
    POJ 1037 (计数 + DP) 一个美妙的栅栏
    HDU 3448 Bag Problem
    HDu 3449 (有依赖的01背包) Consumer
    POJ 1456 (贪心+并查集) Supermarket
    POJ 2236 (简单并查集) Wireless Network
    POJ 1703 Find them, Catch them
  • 原文地址:https://www.cnblogs.com/whistle13326/p/7569520.html
Copyright © 2011-2022 走看看