[openjudge]盒子与小球之三(dp)

题目描述

传送门

题解

这道题其实是可以盒子空着不放的。。。
f(i,j)表示前i个盒子里放了j个小球的方案数。那么
f(i,j)=p=0min(j,k)f(i1,jp) ,也就是枚举最后一个盒子放了几个小球。
这样暴力dp是 O(n3) 的。可以发现加一个滚动和前缀和就可以优化成 O(n2)

代码

O(n3)

#include
#include
#include
using namespace std;
#define Mod 1000007
#define N 5005

int n,m,k;
int f[N][N];

int main()
{
    scanf("%d%d%d",&m,&n,&k);

    f[0][0]=1;
    for (int i=1;i<=n;++i)
    {
        f[i][0]=1;
        for (int j=1;j<=m;++j)
        {
            for (int p=0;p<=min(j,k);++p)
                f[i][j]=(f[i][j]+f[i-1][j-p])%Mod;
        }
    }
    printf("%d\n",f[n][m]);
}

O(n2)

#include
#include
#include
using namespace std;
#define Mod 1000007
#define N 5005

int n,m,k;
int f[2][N],s[2][N];

int main()
{
    scanf("%d%d%d",&m,&n,&k);

    f[0][0]=1;
    for (int i=0;i<=5000;++i) s[0][i]=1;
    for (int i=1;i<=n;++i)
    {
        memset(f[i&1],0,sizeof(f[i&1]));f[i&1][0]=1;
        memset(s[i&1],0,sizeof(s[i&1]));s[i&1][0]=1;
        for (int j=1;j<=m;++j)
        {
            f[i&1][j]=(f[i&1][j]+s[(i-1)&1][j])%Mod;
            if (j-min(j,k)-1>=0) f[i&1][j]=((f[i&1][j]-s[(i-1)&1][j-min(j,k)-1])%Mod+Mod)%Mod;
            s[i&1][j]=(s[i&1][j-1]+f[i&1][j])%Mod;
        }
        for (int j=m+1;j<=5000;++j) s[i&1][j]=s[i&1][j-1];
    }
    printf("%d\n",f[n&1][m]);
}

你可能感兴趣的:(题解,dp)