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; }