2011 Asia Beijing Regional Online Contest-1006 hdu4045 Machine scheduling

2 篇文章 0 订阅
1 篇文章 0 订阅

题意:给4个数n,r,k,m,求从n中选r个数(至少间隔k )并将这r个数分成至多m组一共有多少种情况。

输入为5 2 3 2时
Sample input means you can choose 1 and 4,1 and 5,2 and 5 in the same day.
And you can make the machines in the same group or in the different group.
So you got 6 schemes.
1 and 4 in same group,1 and 4 in different groups.
1 and 5 in same group,1 and 5 in different groups.
2 and 5 in same group,2 and 5 in different groups.
We assume 1 in a group and 4 in b group is the same as 1 in b group and 4 in a group.(注意)

很简单的组合数学加递推题

n个数中取r个使其中间隔至少为k可以用插板法:先将r个球排好并在每两个相邻数之间插入k-1个球,然后将剩下的n-r-(k-1)*(r-1)个板插入到那些球之间,其实只要在n个球中选n-r-(k-1)*(r-1)个作为板就行了。总可能情况数为 c(n,n-r-(r-1)*(k-1))

将r个数分成最多m组推出递推关系:用dp[r][m]代表r个数最多分成m组有多少种情况,rec[r][m]代表r的数恰好分成m组有多少种情况

则 dp[r][m]=rec[r][0]+rec[r][1]+......rec[r][m]

rec[r][m] = rec[r-1][m-1]+(r-1)*rec[r-1][m]   (若第r个数另成一组有rec[r-1][m-1]种情况,若将第r个数插入前面的组中有(r-1)*rec[r-1][m]种情况



#include <iostream>
#include <memory.h>
#include <cstdio>

using namespace std;

const long long MOD = 1000000007;
long long dp[1005][1005];
int com[2015][2015];
long long rec[1005][1005];

void init()
{
    memset(rec,0,sizeof(rec));
    memset(com,0,sizeof(com));
    memset(dp,0,sizeof(dp));
    com[0][0] = 1;
    for(int i=1;i<=2010;i++)
    {
        com[i][0] = com[i][i] = 1;
        for(int j=1;j<i;j++)
        {
            com[i][j]=com[i-1][j-1]+com[i-1][j];
            com[i][j] %= MOD;
        }
    }
    rec[0][0] = 1;
    for(int i=1;i<=1002;i++)
    {
        for(int j=1;j<=1002;j++)
        {
            rec[i][j] = rec[i-1][j-1]+j*rec[i-1][j]%MOD;
            rec[i][j] %= MOD;
            dp[i][j] = dp[i][j-1]+rec[i][j];
            dp[i][j] %= MOD;
        }
    }
}

int main()
{
    int n,r,k,m,tmp;
    init();
    while(scanf("%d%d%d%d",&n,&r,&k,&m)!=EOF)
    {
        tmp = n-r-(r-1)*(k-1);
        if(tmp<0) printf("0\n");
        else
        {
            printf("%I64d\n",(long long)com[tmp+r][r]*dp[r][m]%MOD);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值