【原创】【组合数学】HDU 4248 A Famous Stone Collector

A Famous Stone Collector

题目

Description

Mr. B loves to play with colorful stones. There are n colors of stones in his collection. Two stones with the same color are indistinguishable. Mr. B would like to
select some stones and arrange them in line to form a beautiful pattern. After several arrangements he finds it very hard for him to enumerate all the patterns. So he asks you to write a program to count the number of different possible patterns. Two patterns are considered different, if and only if they have different number of stones or have different colors on at least one position.

Input

Each test case starts with a line containing an integer n indicating the kinds of stones Mr. B have. Following this is a line containing n integers - the number of
available stones of each color respectively. All the input numbers will be nonnegative and no more than 100.

Output

For each test case, display a single line containing the case number and the number of different patterns Mr. B can make with these stones, modulo 1,000,000,007,
which is a prime number.

Sample Input

3
1 1 1
2
1 2

Sample Output

Case 1: 15
Case 2: 8

Hint

In the first case, suppose the colors of the stones Mr. B has are B, G and M, the different patterns Mr. B can form are: B; G; M; BG; BM; GM; GB; MB; MG; BGM; BMG; GBM; GMB; MBG; MGB.

翻译

Mr.B有n种颜色的石头,每种颜色的石头有A[i]个,用石头摆图案,求图案的方案数。
其实就相当于有n种颜色的小球,每种颜色有一定的数量,小球除了颜色没有区别,求方案数。

分析

状态转移方程式:
dp[i][j]//表示用到第i种颜色,用了j块石头
=dp[i-1][j-k]*C[j][k](0<=k<=min(A[i],j))

我们枚举k,表示我们放了k个i颜色石头,
所以说,前面i-1个颜色就占了j-k个位置,而这么放的方案数已知,因此要加上dp[i-1][j-k],
还有k个位置,这k个位置有多少种情况呢?就是C(n,k)//C是组合

预处理组合数就行了,最后注意精度、取模以及多组数据。

代码

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
#define ll long long
#define mod 1000000007

ll C[10005][105],dp[105][10005];
void Sc()
{
    C[0][0]=1LL;
    for(int i=1;i<=10000;i++)
    {
        C[i][0]=1LL;
        for(int j=1;j<=100&&j<=i;j++)
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    }
}

int n,A[105];

int main()
{
    Sc();
    int cr=0;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++) scanf("%d",&A[i]);
        ll sig=0LL;
        memset(dp,0,sizeof dp);
        dp[0][0]=1;
        for(int i=1;i<=n;i++)
        {
            sig+=A[i];
            for(ll j=0;j<=sig;j++)
                for(ll k=0;k<=A[i]&&k<=j;k++)
                    dp[i][j]=(dp[i][j]+dp[i-1][j-k]%mod*C[j][k]%mod)%mod;
        }
        ll ans=0LL;
        for(ll i=1;i<=sig;i++)
            ans+=dp[n][i],ans%=mod;
        printf("Case %d: ",++cr);
        cout<<ans<<endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值