一个袋子中有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
因为要保证“最后一个球总是在编号比他大的球拿完之前拿完”,所以其实最后一个球的顺序是固定的,就是1、2、3...n。那么每一种颜色的球可以摆的个数就是c[i]-1个。
然后从颜色1开始放,可以选择的空的位置为empty,就有empty种方法。放了之后,空的位置就加1,放颜色相同的下一个球就有empty+1种方法,以此类推。把一种颜色相同的球都放完之后,想着要去除以放的颜色相同球的阶乘,这时发现是组合数学的东西了,即C[empty+c[i]-1][c[i]]。
一开始硬算,WA。取余那里有问题又不知道怎么搞。
然后发现球的总数目不超过1000,可以先打出表来,再搞。
代码:
#pragma warning(disable:4996)
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
#include <set>
#include <queue>
#include <stack>
#include <map>
using namespace std;
typedef long long ll;
#define mod 1000000007
int k;
ll res, sum;
int c[1005];
long long C[1050][1050];
void init()
{
int i, j;
for (i = 0; i <= 1000; i++)
{
for (j = 0; j <= i; j++)
{
if (j == 0 || j == i)
C[i][j] = 1;
else
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
}
}
}
void input()
{
int i;
scanf("%d", &k);
sum = 0;
for (i = 1; i <= k; i++)
{
scanf("%d", &c[i]);
c[i] = c[i] - 1;
}
}
void solve()
{
ll empty = 1;//当前有多少空位
res = 1;
int i,kk;
for (i = 1; i <= k; i++)
{
res = (res*C[empty+c[i]-1][c[i]]) % mod;
empty = empty + c[i] + 1;
}
cout << res << endl;
}
int main()
{
//freopen("i.txt","r",stdin);
//freopen("o.txt","w",stdout);
init();
input();
solve();
//system("pause");
return 0;
}