hdu 4045 隔板法+第二类斯特林数

A Baidu’s engineer needs to analyze and process large amount of data on machines every day. The machines are labeled from 1 to n. On each day, the engineer chooses r machines to process data. He allocates the r machines to no more than m groups ,and if the difference of 2 machines’ labels are less than k,they can not work in the same day. Otherwise the two machines will not work properly. That is to say, the machines labeled with 1 and k+1 can work in the same day while those labeled with 1 and k should not work in the same day. Due to some unknown reasons, the engineer should not choose the allocation scheme the same as that on some previous day. otherwise all the machines need to be initialized again. As you know, the initialization will take a long time and a lot of efforts. Can you tell the engineer the maximum days that he can use these machines continuously without re-initialization.
Input
Input end with EOF.
Input will be four integers n,r,k,m.We assume that they are all between 1 and 1000.
Output
Output the maxmium days modulo 1000000007.
Sample Input
5 2 3 2
Sample Output
6

题目大概意思就是说有n个机器,每天选择r个机器,这任意r个机器编号差必须 > = k,并且将它们分成不到m个相同的组,一共多少方案?

很容易想到把 k个机器绑在一起,然后剩下的机器用插空的方法放入 就是r个机器 有r+1个空挡,剩下的机器数为 e=n-k*(r-1)-1 把e分到 r+1个空位 允许 有空,所以 就是
用隔板就变成了 有e+r+1 个总数 有 e+r个空位 选择 r+1-1个 就可以分成 r+1组了

一个好的例题:
例1将20个大小形状完全相同的小球放入3个不同的盒子,允许有盒子为空,但球必须放完,有多少种不同的方法?
分析:本题中的小球大小形状完全相同,故这些小球没有区别,问题等价于将小球分成三组,允许有若干组无元素,用隔板法.
解析:将20个小球分成三组需要两块隔板,因为允许有盒子为空,不符合隔板法的原理,那就人为的再加上3个小球,保证每个盒子都至少分到一个小球,那就符合隔板法的要求了(分完后,再在每组中各去掉一个小球,即满足了题设的要求)。然后就变成待分小球总数为23个,球中间有22个空档,需要在这22个空档里加入2个隔板来分隔为3份,共有C(22,2)=231种不同的方法.
点评:对n件相同物品(或名额)分给m个人(或位置),允许若干个人(或位置)为空的问题,可以看成将这n件物品分成m组,允许若干组为空的问题.将n件物品分成m组,需要m-1块隔板,将这n件物品和m-1块隔板排成一排,占n+m-1位置,从这n+m-1个位置中选m-1个位置放隔板,因隔板无差别,故隔板之间无序,是组合问题,故隔板有Cn+m-1 m-1种不同的方法,再将物品放入其余位置,因物品相同无差别,故物品之间无顺序,是组合问题,只有1种放法,根据分步计数原理,共有Cn+m-1 m-1×1=Cn+m-1 m-1种排法

如果元素互不相同组别相同,用组合数公式(斯特林数)即可,但是元素相同,组别不同,就要用隔板法,这里的桃子是一样的,所以用隔板法分给不同的猴子。

一开始剩下的机器就是元素是相同的,然后组别不同,用隔板法就好,隔板后,每一组机子数量不同就变成了元素不同,分成组别相同的m组 用斯特林数

然后就是 把选出来的r个分成m组,可以为空,那么就是第二类斯特林数了

for(int i=0;i<1005;i++)
    dp[i][i]=1;
for(int i=1;i<1005;i++)
{
    for(int j=1;j<i;j++)
        dp[i][j]=(j*dp[i-1][j]+dp[i-1][j-1])%mod;
}
板子

原理的话也很简单。。可以搜一下。。
然后全部加上就好再*就好。

#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
typedef long long ll;
ll C[2010][2010];
ll dp[1010][1010];
ll ans[2010];
void init(){

    for(int i=1;i<2001;i++)
    {
        C[i][0]=1,C[i][i]=1;
        for(int j=1;j<i;j++)
        {
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
        }
    }

    for(int i=0;i<1005;i++)
        dp[i][i]=1;
    for(int i=1;i<1005;i++)
    {
        for(int j=1;j<i;j++)
            dp[i][j]=(j*dp[i-1][j]+dp[i-1][j-1])%mod;
    }


}

int main()
{
    int n,r,k,m;
    init();
    while(scanf("%d%d%d%d",&n,&r,&k,&m)!=EOF)
    {
        int e=n-(r-1)*k-1;
        if(e<0)
        {
            printf("0\n");
            continue;
        }
        ll res=C[e+r][r];
        long long sum=0;
        for(int i=0;i<=m;i++) sum=(sum+dp[r][i])%mod;
        ll sum1=res*sum;
        sum1%=mod;
        printf("%lld\n",sum1 );
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值