hdu4248 A Famous Stone Collector

本文介绍了一个有趣的算法问题:如何计算不同颜色的宝石排列成美丽图案的数量。通过使用插空法和动态规划技巧,解决了该问题并给出了具体实现代码。

A Famous Stone Collector

Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 19    Accepted Submission(s): 4


Problem 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.
 

Source


唉……比赛的时候写了好久。。然后100的组合数好像有算错,比赛后瞎搞了一番结果AC了。

题意是输入每种颜色有多少石头,问总共有多少种排法,石头可以不用上。

用插空法做,假设已经放了t个石头,则有t+1个空位,这时候新来的k一种石头就可以放在这t+1个空位上。

假设F(i,j)表示现在有i个空格,要放j个石头。

那么F(i,j)=sum(F(t,j-t)*C(i,t)),0<=t<=min(i,j),C()表示组合数

枚举t表示想将这j个石头放在t个空位里,因此C(i,t)不难理解,就是在i个空位里选t个放,然后将这t个空位每个空位放一个石头,剩下j-t个石头需要再放到这t个空位里,但是允许这t个空位中有部分空位不放,因此就是F(t,j-t),即在这t个空位中放j-t个石头。

比赛的时候的代码,搓死……

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

#define MOD 1000000007

int a[105];
long long c[10005][105];
long long cc[10005][105];
long long dp[10005];

void C()
{
    int i,j;
    long long t;
    for (i=0;i<=10002;i++)
    {
        if (i==102) t=1;
        if (i>102) t=(t*i)%MOD;
        for (j=0;j<=min(i,102);j++)
        {
            if (i==0 || j==0 || i==j) c[i][j]=1;
            else if (j==102) c[i][j]=t;
            else c[i][j]=(c[i-1][j-1]+c[i-1][j])%MOD;
        }
    }
}


long long Com(int i,int j)
{
    if (i==1 || j==0) return 1;
    if (cc[i][j]!=-1) return cc[i][j];
    long long ans=0;
    for (int t=1;t<=min(i,j);t++)
    {
        ans=(ans+Com(t,j-t)*c[i][t])%MOD;
    }
    cc[i][j]=ans;
    return ans;
}

int main()
{
    int i,j,n,m,k,cnt=1;
    long long ans,tag;
    memset(cc,-1,sizeof(cc));
    C();
    while(scanf("%d",&n)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        m=0;
        for (i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            for (j=m;j>=0;j--)
            {
                for (k=1;k<=a[i];k++)
                {
                    tag=dp[j]*Com(j+1,k)%MOD;
                    dp[j+k]=(dp[j+k]+tag)%MOD;
                }
            }
            m+=a[i];
        }
        ans=0;
        for (i=1;i<=m;i++)
        {
            ans=(ans+dp[i])%MOD;
        }
        printf("Case %d: %I64d\n",cnt++,ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值