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(p,k)的递推公式是:S(p,k)=k*S(p-1,k)+S(p-1,k-1) ,1<= k<=p-1
边界条件:

S(p,p)=1 ,p>=0

S(p,0)=0 ,p>=1

然后 方案数为 : S[n][1] + S[n][2] + ... + S[n][m]

然后两个结果相乘即可得出答案。

注意取模。

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#define Mod 1000000007
#define lll __int64
using namespace std;

lll dp[1009][1009],sum[1009][1009];
lll S[1009][1009];

int main()
{
    int n,r,k,m;
    int i,j;
    for(i=1;i<=1000;i++)
        S[i][i] = 1, S[i][0] = 0;
    S[0][0] = 0;
    for(int p=1;p<=1000;p++)
        for(int k=1;k<=p-1;k++)
        S[p][k]=((k*S[p-1][k]%Mod+S[p-1][k-1])%Mod+Mod)%Mod;

    while(scanf("%d%d%d%d",&n,&r,&k,&m)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        memset(sum,0,sizeof(sum));
        for(i=1;i<=n;i++)
            dp[i][1] = i, sum[i][1] = (sum[i-1][1] + dp[i][1])%Mod;
        for(j=2;j<=r;j++)
        {
            for(i=k+1;i<=n;i++)
            {
                dp[i][j] = sum[i-k][j-1]%Mod;
                sum[i][j] = (sum[i-1][j] + dp[i][j])%Mod;
            }
        }
        lll ans=0;
        for(int i=1;i<=m;i++)
            ans+=S[r][i];
        ans%=Mod;
        ans=ans*dp[n][r];
        printf("%I64d
",(ans%Mod+Mod)%Mod);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/whatbeg/p/4100883.html