SDUT 备战省赛专项训练赛(一)组合数学 解题报告

C : Kyoya and Colored Balls CodeForces - 553A

最简洁的题意:
C. Kyoya and Colored Balls
Time Limit: 2000ms
Memory Limit: 262144KB
64-bit integer IO format: %I64d Java class name: (Any)
Submit Status
Kyoya Ootori has a bag with n colored balls that are colored with k different colors. The colors are labeled from 1 to k. Balls of the same color are indistinguishable. He draws balls from the bag one by one until the bag is empty. He noticed that he drew the last ball of color i before drawing the last ball of color i + 1 for all i from 1 to k - 1. Now he wonders how many different ways this can happen.

Input
The first line of input will have one integer k (1 ≤ k ≤ 1000) the number of colors.

Then, k lines will follow. The i-th line will contain ci, the number of balls of the i-th color (1 ≤ ci ≤ 1000).

The total number of balls doesn’t exceed 1000.

Output
A single integer, the number of ways that Kyoya can draw the balls from the bag as described in the statement, modulo 1 000 000 007.

Sample Input
Input
3
2
2
1
Output
3
Input
4
1
2
3
4
Output
1680
Hint
In the first sample, we have 2 balls of color 1, 2 balls of color 2, and 1 ball of color 3. The three ways for Kyoya

1 2 1 2 3
1 1 2 2 3
2 1 1 2 3

题目大意为,有n种球,编号分别为1234….n,每种球有ci个,问有几种取法,能把盒子里的球拿完,要求是每次取完一种球前,编号比他小的球都取完。

思路:从小往大排列,首先一开始只有一个格子可以放,放入(c1-1)个一号球,并把最后一个一号球放最后,这样一共有(c1+1)个格子,然后在这么多格子里放入(c2-1)个二号球,并把最后一个二号球放在最后,这样一直到最后。
对于 n个格子里放m个球,打个表球行。n个格子放m个球 放的种类就是(n-1个格子放0,1,2,3,4,….mg个球)求和, 推倒一下很容易得到(n个格子放m个球)=(n-1格子放m个球)+(n格子放m-1个球)。这就是推导公式。

2 思路:可以知道涂颜色k的最后一个球一定在最后一个位置上,那么剩下的a[k]-1个球就可以在n-1个位置任意摆放,有C(a[k]-1,n-1)种放法。然后颜色为k-1的最后一个球就摆放在颜色为k球的前面一位,剩下的a[k-1]-1个球就可以在n-a[k]-1的位置上摆放,有C(a[k-1]-1,n-a[k]-1)种放法。

依次类推,直到所有的球都放完。那么答案就是上述的放法相乘然后取模。

但是对于C(m,n),虽然我们可以通过阶乘A(m,n)/A(m,m)计算,但是数据范围一大,long long范围下就存不下了,如果采用取模方式,就会出错。

所以我们想到了一个公式:C(m,n)=C(m,n-1)+C(m-1,n-1)。

那么我们就可以设一个数组来记录下C(m,n)的答案。

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
using namespace std;

const int mod =  1e9+7;
const int maxn=  2005;
long long s[maxn][maxn]={0};
int a[maxn];
int main()
{
    for(int i=0;i<maxn;i++)
        s[i][0]=  1;
    for(int i=1;i<maxn;i++)
    {
        for(int j=1;j<=i;j++)
        {
            if(i==j)s[i][j] = 1;
            else if(i>j)
            s[i][j] = (s[i-1][j]+s[i-1][j-1])%mod;
        }
    }
    int t;
   cin>>t;
    int ans = 1;
    int sum = 0;
    for(int i=1;i<=t;i++)
    {
        cin>>a[i];
        sum+=a[i];
    }
    for(int i=t;i>=1;i--)
    {
        //if(a[i]==0)a[i]++;
        ans = (ans*s[sum-1][a[i]-1])%mod;
        sum-=a[i];
        ans = ans%mod;
    }
    cout<<ans<<endl;
    return 0;
}
全部评论

相关推荐

大方的大熊猫准备进厂:1.教育背景:你希望从事什么专业的工作你的主修课就是什么;成绩优秀是你应该做的,没什么可描述的,成绩不优秀也许人家在大学忙着创业呢?(成绩优秀不一定是好事,只能说明多元化的大学你上成了高中,没有真正上明白大学,反而体现了你死板,不爱社交,没有别的突出能力) 2.实践经历:你想表达的意思没有说清楚。你是说你会个性化服务,还是你有实习经历。如果没有带来,经济收益,表彰,更好的发展前景,那你还不如说说提升了自己哪些技能。你说有人给你送锦旗我都能明白你优秀,但是你说你会xxxx,你说这话谁信,证据呢。 3.入伍经历:你描述的就是你的工作职责或者你应该做的,并没有体现出来你把这个事情做好了,而且入伍经历并不能证明你能干好你要应聘的工作,不如只写经历其余所有内容都不写。 4.荣誉技能:重点突出一下,但不要过多描述,这些荣誉的含金量懂得都懂。 重点:你要应聘什么工作(具体岗位,实习生不具体),你的期望薪资
点赞 评论 收藏
分享
05-01 22:41
中南大学 Java
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务