• 【BZOJ 3027】 3027: [Ceoi2004]Sweet (容斥原理+组合计数)


    3027: [Ceoi2004]Sweet

    Time Limit: 1 Sec  Memory Limit: 128 MB
    Submit: 71  Solved: 34

    Description

    John得到了n罐糖果。不同的糖果罐,糖果的种类不同(即同一个糖果罐里的糖果种类是相同的,不同的糖果罐里的糖果的种类是不同的)。第i个糖果罐里有 mi个糖果。John决定吃掉一些糖果,他想吃掉至少a个糖果,但不超过b个。问题是John 无法确定吃多少个糖果和每种糖果各吃几个。有多少种方法可以做这件事呢?  

    Input


    从标准输入读入每罐糖果的数量,整数a到b 
     
    John能够选择的吃掉糖果的方法数(满足以上条件)  
     

    Output


     
    把结果输出到标准输出(把答案模 2004 输出) 

    1<=N<=10,0<=a<=b<=10^7,0<=Mi<=10^6

    Sample Input

    2 1 3
    3
    5

    Sample Output

    9

    HINT

    (1,0),(2,0),(3,0),(0,1),(0,2),(0,3),(1,1),(1,2),(2,1) 

    Source

     
    【分析】
      就是分成(<=b) - (<= a-1)的。
      然后每个糖果罐容斥,枚举哪些超过了的。
      假设减掉之后剩下最多选x个糖果
      就是$C_{0+n-1}^{n-1}+C_{1+n-1}^{n-1}+C_{2+n-1}^{n-1}+...+C_{x+n-1}^{n-1}$
      求和之后就是$C_{x+n}^{n}$
      但是!!!模数可能没有逆元,又不能n^2预处理。。
      【怎么办呢???
      【又涨姿势。。
      首先都是$C_{x}^{n}$的形式,即$dfrac{x!}{(x-n )!}/(n!)$
      n!很小,让$mod=Mod*n!$
      计算的时候模mod,最后除以n!,再模Mod。。。
      就可以了。
     
     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 using namespace std;
     7 #define Mod 2004
     8 #define Maxm 10000010
     9 #define LL long long
    10 
    11 int w[15],n;
    12 LL mul;
    13 
    14 int get_c(int x,int y)
    15 {
    16     if(x<y) return 0;
    17     LL mod=mul*Mod,ans=1;
    18     for(int i=x;i>=x-y+1;i--) ans=1LL*ans*i%mod;
    19     return (ans/mul)%Mod;
    20 }
    21 
    22 int cal(int x)
    23 {
    24     int ans=0;
    25     for(int i=0;i<(1<<n);i++)
    26     {
    27         int ss=0,sm=x;
    28         for(int j=1;j<=n;j++) if((1<<j-1)&i)
    29         {
    30             ss++;sm-=w[j]+1;
    31         }
    32         if(sm<0) continue;
    33         if(ss&1) ans-=get_c(sm+n,n);
    34         else ans+=get_c(sm+n,n);
    35         ans%=Mod;
    36     }
    37     return ans;
    38 }
    39 
    40 int main()
    41 {
    42     int a,b;
    43     scanf("%d%d%d",&n,&a,&b);
    44     mul=1;for(int i=2;i<=n;i++) mul=mul*i;
    45     for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    46     printf("%d
    ",((cal(b)-cal(a-1))%Mod+Mod)%Mod);
    47     return 0;
    48 }
    View Code

    2017-04-25 21:25:39

  • 相关阅读:
    C#中Equals和= =(等于号)的比较)(转载)
    C# 控制台应用程序输出颜色字体
    c#获取当前运行程序所在的目录
    java环境配置
    c#随机产生颜色
    Git学习
    git删除所有提交历史记录
    git忽略项gitegnore配置
    不搭建git服务器对git仓库进行局域网内共享多人合作开发项目
    搭建Git服务器-SCM-Manager
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6764427.html
Copyright © 2020-2023  润新知