HDU 4045 Machine scheduling (第二类斯特林数+DP)

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.

InputInput end with EOF. 
Input will be four integers n,r,k,m.We assume that they are all between 1 and 1000. 
OutputOutput the maxmium days modulo 1000000007. 
Sample Input

5 2 3 2

Sample Output

6

Hint

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.

题意,现在有1到n,n个数,从中选出r个数,要求选出的数的差至少为k,最后把选出的数放入不大于m个没有差异的盒子里面,问有多少种方案?取模1E9+7

分析:

需要进行两步操作,第一步是要选出r个数,求出共有多少种方案

第二步是在已经有了r个数,那么这r个数的具体值就不重要了,只需求把这r个数放入盒子里的方案数。

最后将两步的结果相乘

对于第一步操作:可以用dp[i][j]表示 数i是第j个数的方案数量

dp[i][j]=(dp[i][j]+dp[z][j-1])%MOD (z表示从1到i-k的数)

但是这样需要三重循环,所需时间超过数据范围

而这里实际上只与前(i-k)个的和有关,所以要用滚动数组的方式进行预处理

第二步:如果是刚好放入m个盒子,就是第二类斯特林数。但这里是放入不大于m个盒子,所以看做刚好放入(1到m)个盒子的第二类斯特林数求和

代码如下:

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long LL;
LL stl[1100][1100];
LL sumstl[1100][1100];
LL dp[1100][1100];
LL d[1100];
LL d2[1100];
const int MOD=1e9+7;
void init()
{
  for(int i=1;i<=1000;i++)
  stl[i][i]=1;

  for(int i=1;i<=1000;i++)
   for(int j=1;j<i;j++)
     stl[i][j]=(stl[i-1][j-1]+j*stl[i-1][j]%MOD)%MOD;

  for(int i=1;i<=1000;i++)
    for(int j=1;j<=1000;j++)
     sumstl[i][j]=(sumstl[i][j-1]+stl[i][j])%MOD;
}
int main()
{
     LL n,r,k,m,sum,ans;
     init();
     while(scanf("%lld%lld%lld%lld",&n,&r,&k,&m)!=EOF)
     {
         sum=0;
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
        {
        dp[i][1]=1;
        d[i]=(d[i-1]+dp[i][1])%MOD;
        }
         for(int j=2;j<=r;j++)
        {
           for(int i=1;i<=n;i++)
          {
              if(i-k>=0)
            dp[i][j]=(dp[i][j]+d[i-k])%MOD;
            d2[i]=(d2[i-1]+dp[i][j])%MOD;
          }
          for(int z=1;z<=n;z++)
           d[z]=d2[z];
        }
        for(int i=1;i<=n;i++)
        sum=(sum+dp[i][r])%MOD;
     //   cout<<sum<<endl;
        ans=(sum*sumstl[r][m])%MOD;
        cout<<ans<<endl;
     }
    return 0;
}

原文地址:https://www.cnblogs.com/a249189046/p/8411106.html

时间: 2024-10-09 23:08:08

HDU 4045 Machine scheduling (第二类斯特林数+DP)的相关文章

HDU 4045 Machine scheduling (组合数学-斯特林数,组合数学-排列组合)

Machine scheduling Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1000    Accepted Submission(s): 363 Problem Description A Baidu's engineer needs to analyze and process large amount of data o

HDU 4045 Machine scheduling --第二类Strling数

题意: n个数(1~n)取出r个数,取出的数相差要>=k, 然后分成m个可空组,问有多少种情况. 解法: 先看从n个数中取r个相差>=k的数的方法数,可以发现 dp[i][j] = dp[1][j-1] + dp[2][j-1] + ... + dp[i-k][j-1],(dp[i][1] = i)  即维护一个前缀和即可,可以在O(r*n)内得出. 然后n个不同的数分成m个可以空的组,即为第二类Strling数的和 : S[n][1] + S[n][2] + ... + S[n][m]. S

hdu 2512 一卡通大冒险(第二类斯特林数)

递推思路如下,i张卡片分成j堆,那么分为两种情况:第i张卡片自成一堆或没有自成一堆. 那么自成一堆的话就是dp[i-1][j-1]种情况 不自成一堆的话就是就能在j堆种任意挑一堆放入,所以有dp[i-1][j]*j种情况 综上,如下: dp[i][j]=dp[i-1][j]*j+dp[i-1][j-1]. 关于第二类斯特林数,百度就好. 具体代码 #include <iostream> using namespace std; int dp[2005][2005]; int main() {

Gym 101147G 第二类斯特林数

大致题意: n个孩子,k场比赛,每个孩子至少参加一场比赛,且每场比赛只能由一个孩子参加.问有多少种分配方式. 分析: k>n,就无法分配了. k<=n.把n分成k堆的方案数乘以n的阶乘.N分成k堆得方案数即第二类斯特林数 http://blog.csdn.net/acdreamers/article/details/8521134 #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll

Light OJ 1236 Race 第二类斯特林数

第二类斯特林数 n 匹马 分成1 2 3... n组 每一组就是相同排名 没有先后 然后组与组之间是有顺序的 在乘以组数的阶乘 #include <cstdio> #include <cstring> using namespace std; int dp[1010][1010]; int a[1010]; int main() { a[0] = 1; dp[0][0] = 1; for(int i = 1; i <= 1000; i++) { dp[i][0] = 0; d

swjtu oj Paint Box 第二类斯特林数

http://swjtuoj.cn/problem/2382/ 题目的难点在于,用k种颜色,去染n个盒子,并且一定要用完这k种颜色,并且相邻的格子不能有相同的颜色, 打了个表发现,这个数是s(n, k) * k! s(n, k)表示求第二类斯特林数. 那么关键是怎么快速求第二类斯特林数. 这里提供一种O(k)的算法. 第二类斯特林数: #include <cstdio> #include <cstdlib> #include <cstring> #include <

poj 3088 组合计数,第二类斯特林数

题意:给出n个数字[1,n],问你可以组成多少种不同的序列,其中每一个序列由几个部分组成,每个部分包含几个数字,每部分内数字无序,部分之间数字有序.每个数字最多使用一次,可以不用. 思路:枚举从n个数字中选出i个数字(组合数),再枚举将这i个数字分成j个部分(第二类斯特林数),然后乘上j的全排列. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5

LightOJ 1326 - Race(第二类斯特林数啊 )

题目链接:http://lightoj.com/volume_showproblem.php?problem=1326 百度百科:斯特林数 ACdreamer:第一类Stirling数和第二类Stirling Disky and Sooma, two of the biggest mega minds of Bangladesh went to a far country. They ate, coded and wandered around, even in their holidays.

Gym Gym 101147G 第二类斯特林数

题目链接:http://codeforces.com/gym/101147/problem/G 题意:n个人,去参加k个游戏,k个游戏必须非空,有多少种放法? 分析: 第二类斯特林数,划分好k个集合后乘以阶乘: 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1010; 6 const long long MOD = 1000000000 + 7L; 7 long long stir[maxn][