51Nod 1453(CF553-A) - 抽彩球(Kyoya and Colored Balls) - 解题报告

51Nod 1453 - 抽彩球 - 解题报告


  • 51Nod 1453 - 抽彩球 - 解题报告
      • Information
      • Source
      • Description
          • Input
          • Output
      • Sample
          • Scan
          • Print
          • Explanation
      • Solve
          • 方法1:组合数学
          • 方法2:动态规划


Information

time limit 1000ms
memory limit 131072KB
level 四级算法题

Source

Speciality  codeforces-553-A  codeforces-554-C
51Nod -1453      洛谷 - CF553A - Kyoya and Colored Balls
Vjudge - 51Nod - 14531:  地址1  地址2  地址3


Description

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

Input

     单组测试数据。
     第一行给出一个整数k(1 ≤ k ≤ 1000),表示球的种类。
     接下来k行,每行一个整数ci,表示第i种颜色的球有ci个(1 ≤ ci ≤ 1000)。
     球的总数目不超过1000。

Output

     输出总数对1,000,000,007的模即可。

Sample

一组样例,如下:

Scan

     3
     2
     2
     1

Print

     3

Explanation

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


Solve

方法1:组合数学

正确,且速度可观:
放图
至于具体做法,七分靠注释,三分靠自己。代码如下:

#include
#include
#define M 1000
using namespace std;
int k,c[M+2],l[M+2];
long long ans=1,C[M+2][M+2];
const long long WXY=1000000007;
void init() //求组合数
{
    for(int i=0;i<=M;i++)
        C[i][0]=1;
    for(int i=1;i<=M;i++)
        for(int j=1;j<=i;j++)
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%WXY;
}
int main()
{
    init();
    cin>>k;
    for(int i=1;i<=k;i++)
        cin>>c[i];
    l[0]=-1;   //-1是为了除去已经确定位置的彩球
    for(int i=1;i<=k;i++)
        l[i]=l[i-1]+c[i]; //计算每个位置前可以插空的数量
    for(int i=1;i<=k;i++)
        ans=(ans*C[l[i]][c[i]-1])%WXY; //-1是为了除去已经确定位置的彩球
    cout<
方法2:动态规划

本人不才,详见巨佬博客 2


  1. 地址1为中文版,地址2、地址3均为英文版。此外,若无法查看或网页加载较慢,可在vjudge.net前添加cn. ╮(╯_╰)╭ ↩
  2. (+﹏+)~ 请前往CSDN、博客园寻找『回头补上 然鹅,一万年过去了』 ↩

你可能感兴趣的:(动态规划,排列组合)