http://acm.hdu.edu.cn/showproblem.php?pid=4045
题意: n个机器,每天选择r个机器,这任意r个机器编号差>=k,并且将它们分成不到m个相同的组,一共多少方案?
一是 把n机器每天选r个 编号差》k的方案
二是把r个机器分成小于等于m个组的方案
二者乘积就是答案
对于1: 既然要编号差大于等于k,先令每个机器间编号差为k,那么剩下 res=n-k*(n-1)-1个机器没用
接下来把res个机器插到 空隙中,根据插板法,在r个机器的r+1个空隙中插res个机器的方案为 :C(r+res,r)
第二种情况就是Stirling(r,m)
注意取模:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <iostream>
using namespace std;
const long long mod=1000000007;
int ss[1005][1005];
int cc[2005][2005]; //内存限制为 C(n,k)中的n*k
void pre()
{
int i,j;
for (i=0; i<=2000; i++)
{
cc[i][0]=1; //c(i,0)=1;
}
for (i=1; i<=2000; i++)
{
for (j=1; j<=2000; j++)
cc[i][j]=(cc[i-1][j-1]+cc[i-1][j])%mod;
}
}
void spre()
{
for (int i=1; i<=1000; i++)
ss[i][0]=0;
for (int i=0; i<=1000; i++)
ss[i][i]=1;
for (int i=1; i<=1000; i++)
{
for (int j=1; j<=i-1; j++)
{
ss[i][j]=(j*(long long )ss[i-1][j]%mod+ss[i-1][j-1])%mod;
}
}
}
int main()
{
pre();
spre();
int n,k,r,m;
while(scanf("%d%d%d%d",&n,&r,&k,&m)!=EOF)
{
long long res=n-(r-1)*k-1;
if (res<0)
{
printf("0\n");continue;
}
long long ans=0;
for (int i=0; i<=m; i++)
ans=(ans+ss[r][i])%mod;
ans*=cc[res+r][r];
printf("%lld\n",ans%mod);
}
}