描述
题解
很好地一道题,可以用dp解(Two),也可以用插空法(One),然而,由于dp实在不好理解,我也没能彻悟,所以这里介绍一下插空法。
从后往前推,把第k种颜色放在最后一个,剩下的k球,有C(剩余的空位置,k球总数-1)种放置方法,然后讨论第k-1种,以此类推下去……由于组合比较大,需要用乘法逆元,也可以直接套Lucas。
至于dp的解法,我看得不是太懂,具体的思路可以去大牛光速小子0511的博客里看,��,暂时理解不了,我太笨了……
代码
One:
#include <stdio.h>
#define LL long long
const LL MOD = 1e9 + 7;
const int MAXN = 1e3 + 5;
const int MAXM = 1e6 + 5;
int n;
int a[MAXN];
LL fac[MAXM];
LL ppow(LL x, LL y)
{
LL c = 1;
while (y)
{
if (y & 1)
{
c = c * x % MOD;
}
y >>= 1;
x = x * x % MOD;
}
return c;
}
LL work(LL m, LL i)
{
return ((fac[m] % MOD) * (ppow((fac[i] * fac[m-i]) % MOD, MOD - 2) % MOD)) % MOD;
}
int main()
{
fac[0] = 1;
for(int i = 1; i < MAXM; i++)
{
fac[i] = (fac[i - 1] * i) % MOD;
}
LL ans = 1,sum = 0;
scanf("%d", &n);
for(int i = 1; i<= n; i++)
{
scanf("%d", a + i);
sum += a[i];
}
for(int i = n; i >= 1; i--)
{
ans *= work(sum - 1, a[i] - 1);
ans %= MOD;
sum -= a[i];
}
printf("%lld\n", ans);
return 0;
}
Two:
#include <iostream>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
const int MAXN = 1e3 + 5;
int k;
ll res, sum;
int c[MAXN];
long long C[MAXN][MAXN];
void init()
{
for (int i = 0; i < MAXN; i++)
{
for (int 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;
}
}
}
return ;
}
void input()
{
scanf("%d", &k);
sum = 0;
for (int i = 1; i <= k; i++)
{
scanf("%d", &c[i]);
c[i]--;
}
return ;
}
void solve()
{
ll empty = 1; // 当前有多少空位
res = 1;
for (int i = 1; i <= k; i++)
{
res = (res * C[empty + c[i] - 1][c[i]]) % MOD;
empty = empty + c[i] + 1;
}
cout << res << endl;
return ;
}
int main()
{
init();
input();
solve();
return 0;
}