题目链接:https://vjudge.net/problem/HDU-4045
Machine scheduling
Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1907 Accepted Submission(s): 702
Input will be four integers n,r,k,m.We assume that they are all between 1 and 1000.
题意:
从1~n中选出r个数,要求这r个数之间每对数的差值大于等于k;选出之后,再将这r个数分成m组。问总共有多少种方案?
题解:
问题分为两个部分进行求解:
1.如果正确选出这r个数呢?
如图,O代表选出的r个数,双下划线代表相邻两个数之间的差值。由于数字从1开始,所以最左边应该填上1;由于相邻两个数之间差值最小为k,所以出于中间的下划线应该填上k,这样就满足题目的限定。还剩下 n-1-(r-1)*k,然后再把他们分到r+1个下划线上。根据隔板法,总共有 C[n-1-(r-1)*k+r+1-1][r+1-1] = C[n-1-(r-1)*k+r][r] 。
2.把r个数分成m组,就是第二类斯特林数了。注意r可能小于m, 所以应为 S[r][min(r,m)] 。
3.所以总的方案数为: C[n-1-(r-1)*k+r][r] * S[r][min(r,m)] 。
4.注意,当n<1+(r-1)*k时,即连最基本的条件都满足不了时,方案数为0,需要特判。
代码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const int INF = 2e9; 15 const LL LNF = 9e18; 16 const int MOD = 1e9+7; 17 const int MAXN = 1e3+10; 18 19 LL S[MAXN][MAXN], f[MAXN][MAXN], C[MAXN][MAXN]; 20 21 void init() 22 { 23 for(int i = 0; i<MAXN; i++) 24 { 25 C[i][0] = 1; 26 for(int j = 1; j<=i; j++) 27 C[i][j] = (C[i-1][j-1]+C[i-1][j])%MOD; 28 } 29 30 for(int i = 1; i<MAXN; i++) 31 { 32 S[i][0] = 0; S[i][i] = 1; 33 for(int j = 1; j<i; j++) 34 S[i][j] = ((j*S[i-1][j])%MOD + S[i-1][j-1])%MOD; 35 } 36 37 memset(f, 0, sizeof(f)); 38 for(int i = 1; i<MAXN; i++) 39 for(int j = 1; j<=i; j++) 40 f[i][j] = (f[i][j-1] + S[i][j])%MOD; 41 } 42 43 int main() 44 { 45 init(); 46 int n, r, k, m; 47 while(scanf("%d%d%d%d", &n,&r,&k,&m)!=EOF) 48 { 49 LL ans; 50 if(1+(r-1)*k>n) ans = 0; 51 else ans = (1LL*C[n-1-(r-1)*k+r][r]*f[r][min(r,m)])%MOD; 52 printf("%lld\n", ans); 53 } 54 }