UOJ495 新年的促销(动态规划)

首先考虑一下:如果我们知道要买(或送)哪几袋米,如何确保自己的钱够用?

显然应该买最便宜的几个,剩下的送。

所以我们可以枚举一个$p$,比$p$便宜的米用买的方式,比$p$贵的米用送的方式,不会遗漏最优解。把米按价格排序用背包就可以做到$O(n^2m)$。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define For(i,A,B) for(i=(A);i<=(B);++i)
using namespace std;
struct node{
    int w,p;
}a[305];
int f[2005][305],g[305][305],t[305],ans[2005];
inline bool cmp1(const node &a,const node &b){return a.p<b.p;}
inline bool cmp2(int x,int y){return x>y;}
inline void chkmax(int &a,int b){if(b>a)a=b;}
int main(){
    int n,m,x,y,i,j,k;
    scanf("%d%d%d%d",&n,&m,&x,&y);
    For(i,1,n)scanf("%d",&a[i].w);
    For(i,1,n)scanf("%d",&a[i].p);
    sort(a+1,a+n+1,cmp1);
    For(i,1,n){
        For(j,1,n-i+1)t[j]=a[j+i-1].w;
        sort(t+1,t+n-i+2,cmp2);
        For(j,1,n-i+1)g[i][j]=g[i][j-1]+t[j];
    }
    memset(f,~0x3f,sizeof(f));
    For(i,0,m)f[i][0]=0;
    For(i,1,n)
        for(j=m;j>=a[i].p;--j)
            for(k=i;k;--k){
                chkmax(f[j][k],f[j-a[i].p][k-1]+a[i].w);
                chkmax(ans[j],f[j][k]+g[i+1][min(k/x+k/y,n-i)]);
            }
    For(i,1,m)printf("%d ",ans[i]);
    return 0;
}
View Code

 

posted @ 2020-03-03 10:03  wangyuchen  阅读(168)  评论(0编辑  收藏  举报