[loj6039]珠宝

[loj6039]珠宝


决策单调性优化dp。


不难推出DP式子 dp[i]=max(dp[j]+v_i)-----<(i+c_i<=j),同时我们发现c_i只有300,于是考虑在c_i上做优化。

既然要在c_i上考虑优化,那么我们可以考虑将所有c_i相等的v一起考虑。不难发现,在同一个c_i中,我们一定可以贪心的选最大的几个v,即决策单调。

同时,在同一个c_i中,我们不难发现当i,j之差为c[i]时转移一定最优。所以我们可以考虑对于mod c_i 相等的数一起计算。

我们不难看出这里的决策是单调的。

但是我们并不能用单调队列维护(貌似?),于是我们可以考虑分治。(具体见代码)

  • 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5,M=5e4+5,C=310;
int c[N],v[N];
int n,k,mxc,ind;
ll dp[C][M];
vector<ll>bag[C],buc[C];
bool cmp(const int a,const int b){return a>b;}
int table[N];

ll cal(int id,int lstpos,int now){
    int num=(now-lstpos)/id;
    if(num>(signed)bag[id].size()-1)return -1;
    return dp[id-1][lstpos]+bag[id][num];
}

void solve(int id,int l,int r,int pl,int pr){//"pl,pr为决策点的范围
    int mid=(l+r)>>1;int pos=0;ll maxv=0;
    for(int i=pl;i<=min(mid,pr);i++){
        ll val=cal(id,table[i],table[mid]);
        if(val>maxv)maxv=val,pos=i;
    }
    if(l==r){
        dp[id][table[l]]=maxv;
        return;
    }
    solve(id,l,mid,pl,pos);
    solve(id,mid+1,r,pos,pr);
}

int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&c[i],&v[i]);
        buc[c[i]].push_back(v[i]);
        mxc=max(mxc,c[i]);
    }
    for(int i=1;i<=mxc;i++){
        sort(buc[i].begin(),buc[i].end(),cmp);
        bag[i].push_back(0);
        ll now=0;
        for(int j=0;j<(signed)buc[i].size();j++){
            now+=buc[i][j];
            bag[i].push_back(now);
        }
    }
    for(int i=1;i<=mxc;i++){
        for(int j=0;j<=i-1;j++){//"考虑mod i=j的转移
            table[ind=1]=j;
            while(table[ind]+i<=k){
                table[ind+1]=table[ind]+i;
                ++ind;
            }
            solve(i,1,ind,1,ind);
        }
    }
    for(int i=1;i<=k;i++){
        printf("%lld ",dp[mxc][i]);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_35923186/article/details/82919451