Machine scheduling
Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1588 Accepted Submission(s): 606
Input will be four integers n,r,k,m.We assume that they are all between 1 and 1000.
5 2 3 2
6HintSample 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台不同的机器,编号从1到n。从其中选出r台,要求任意两台的编号之差都不能小于k,将其分成m组。问一共有多少种方案。
n,r,k,m都小于1000.
给出两种思维方法,都很好理解,都要掌握,这很经典,非常经典。
分为两步来做:
第一步是选择r台机器,第二步是对r台机器分配为m组,这是第二类stirling数。
第一种理解:
假设我们选择了r台机器,但是暂时不确定他们的编号。
然后我们往每相邻的两台机器中插入k-1台机器,这样r台机器就满足题目的要求了。
此时,选择了r台机器,向中间填入了(r - 1) * (k - 1)台机器, 一共用去了(r - 1) * (k - 1) + r台
还剩下的机器数为n-(r-1)*k-1,它们可以任意的插入到r+1个区域中。
接下来,对所有的机器从左到右来编号,这就得到了合理的一个方案。那么这一步的方案数为:
C[ n - ((r - 1) * (k - 1) + r) + r + 1 - 1 ][ r ]
最终答案还要乘以S(r,m)
S(r,m)是第二类stirling,表示把r个不同的小球放到m个相同盒子,盒子不能为空的方案数
第二种理解:
选出的r台机器中若相邻两台编号刚好相差为k,则相邻两台之间的空档刚好为k个。
还剩余的空档的数量为(n - 1 - ( r - 1 ) * k)。
这些空档可以插入到r+1个区域中去。这便可以利用隔板法来解决了。
方案数为:
C[ n - ( r - 1 ) * k - 1 + r + 1 - 1 ][ r ] = C[ n - ( r - 1 ) * ( k + 1) ][ r ]
最终答案要乘以S(r,m)
Code:
Status | Accepted |
---|---|
Time | 15ms |
Memory | 19448kB |
Length | 859 |
Lang | G++ |
Submitted | 2017-07-08 20:22:27 |
Shared | |
RemoteRunId | 21030892 |
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
typedef long long LL;
const int MOD = 1e9 + 7;
int C[2005][2005], S2[1005][1005];
void pre_work(){
C[0][0] = 1, S2[0][0] = 1;
for(int i = 1; i <= 2000; ++ i){
C[i][0] = C[i][i] = 1;
for(int j = 1; j < i; ++ j)
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
}
for(int i = 1; i <= 1000; ++ i){
S2[i][0] = 0, S2[i][i] = 1;
for(int j = 1; j < i; ++ j)
S2[i][j] = (S2[i - 1][j - 1] + (LL)S2[i - 1][j] * j) % MOD;//注意溢出
}
}
int main(){
pre_work();
int N, R, K, M;
while(~scanf("%d%d%d%d", &N, &R, &K, &M)){
if(N - ((R - 1) * K + 1) < 0){
puts("0");
continue;
}
int sum = 0;
int x = min(R, M);
for(int i = 1; i <= x; ++ i)
sum = (sum + S2[R][i]) % MOD;
printf("%d\n", (LL)C[N - ((R - 1) * (K - 1) + R) + R + 1 - 1][R] * sum % MOD);//注意溢出
}
return 0;
}