「雅礼集训 2017 Day5」珠宝

题目描述

Miranda 准备去市里最有名的珠宝展览会,展览会有可以购买珠宝,但可惜的是只能现金支付,Miranda 十分纠结究竟要带多少的现金,假如现金带多了,就会比较危险,假如带少了,看到想买的右买不到。展览中总共有 N 种珠宝,每种珠宝都只有一个,对于第 i种珠宝,它的售价为 Ci 万元,对 Miranda 的吸引力为 Vi。Miranda 总共可以从银行中取出 K 万元,现在她想知道,假如她最终带了 i 万元去展览会,她能买到的珠宝对她的吸引力最大可以是多少?

题解

菜死了菜死了。。

因为普通的01背包问题是NP的,所以我们要观察题目中的一些特殊性质。

注意到C非常小,可以把C拿出来做文章。

对于每一个物品体积,我们可以有方程:dp[i]+sum[j-i]->dp[j]

对于C一样的物品,我们要选肯定是要先选价值大的,所以sum数组是一个上凸的。

我们可以对于每个C,再去枚举余数,在相同余数下进行dp。

因为有了上面的结论,那么我们的dp就有了单调性,若i转移到了x,那么(l-x)只会被(L-i)转移,(x-r)只会被(i-R)转移。

可以用分治dp做。

代码

#include
#include
#include
#include
#define M 302
#define K 50002
#define N 1000002
using namespace std;
typedef long long ll;
ll dp[2][K],g[2][K];
int pre,now,pos,n,k,mx;
vectorvec[M];
inline int rd(){
    int x=0;char c=getchar();bool f=0;
    while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return f?-x:x;
}
inline ll cmp(ll x,ll y){return x>y;}
void solve(int l,int r,int L,int R,int sum){
    if(L>R||l>r)return;
    int mid=(L+R)>>1;ll num=0,point=-1;
    for(int i=max(mid-sum,l);i<=r&&ii){
        if(g[pre][i]+vec[pos][mid-i-1]>num){
            num=g[pre][i]+vec[pos][mid-i-1];point=i;
        }
    }
    if(point<0)point=l;
    g[now][mid]=num;
    solve(l,point,L,mid-1,sum);solve(point,r,mid+1,R,sum);
}
int main(){
    n=rd();k=rd();int x,y;
    for(int i=1;i<=n;++i){
        x=rd();y=rd();
        vec[x].push_back(y);mx=max(mx,x);
    }
    now=1;pre=0;
    for(int i=1;i<=mx;++i)if(vec[i].size()){
        pos=i;swap(now,pre);
        sort(vec[i].begin(),vec[i].end(),cmp);int x=vec[i].size(); 
        for(int j=1;j1];
        for(int j=0;jj){
            int p=0;
            for(int l=j;l<=k;l+=i,p++)g[pre][p]=dp[pre][l],g[now][p]=0;p--;
            solve(0,p,0,p,vec[i].size());
            for(int l=j,p=0;l<=k;l+=i,p++)dp[now][l]=max(dp[now^1][l],g[now][p]);
        }
    }
    for(int i=1;i<=k;++i)printf("%lld ",dp[now][i]);
    return 0;
} 

转载于:https://www.cnblogs.com/ZH-comld/p/10458164.html

你可能感兴趣的:(「雅礼集训 2017 Day5」珠宝)