zoukankan      html  css  js  c++  java
  • LOJ 6039 珠宝

    LOJ #6039 珠宝

    题意:

    01背包

    数据范围:

    (1 leq N leq 1000000, 1 leq K leq 50000, 1 leq C_i leq 300, 0 leq V_i leq 10 ^ 9)

    题解:

    考虑每个物品的代价不同的只有不多于 (300) 个,把相同代价的物品分成一类同时进行 (dp)

    先考虑相同代价的物品价值都相同,这就是一个单调队列优化多重背包,把这种思想类比到价值不同的情况下。

    根据贪心,相同代价时肯定优先选择价值高的物品,设 (w_{i,j}) 为取 (j) 个代价为 (i) 的最大价值,显然 (w_{i,j}) 为把所有代价为 (i) 的物品价值按从大到小排序后的前缀和。

    (dp_{i,j}) 为只选了代价小于等于 (i) 的物品且总代价小于等于 (j) 的最大价值,显然我们有转移方程为 (dp_{i,j}=max(dp_{i-1,j-ki}+w_{i,j}))

    但是可以发现 (w_i) 是一个凸函数,并不能直接用单调队列转移(可能后来居上,但单调队列并没有反应)。可以再维护一个 (T)(T_i)(i) 最早被单调队列中下一个决策更劣的时间,可以二分找。

    每次找决策点时,看一看队首是否已经不是最优。插入一个决策点时,如果当前队尾比队尾前一个更优的时间大于等于队尾比新决策点更劣的时间,则这个队尾决策一定不会被用到,直接弹出。

    复杂度为 (mathcal{O}(max(C_i)Klog N))

    代码实现:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    int q[100005],h,t;
    int f[50005],g[50005],T[50005],n,m;
    vector<int>w[305];
    int gettime(int l,int r,int x,int s) {
    	int L=r+1,R=l+w[x].size(),ans=l+w[x].size()+1;
    	while(L<=R) {
    		int mid=(L+R)>>1;
    		if(f[r*x+s]+w[x][mid-r-1]<f[l*x+s]+w[x][mid-l-1]) L=mid+1;
    		else ans=mid,R=mid-1;
    	} return ans;
    }
    void DP(int x) {
    #define I (i*x+s)
    	memset(T,0x3f,sizeof(T));
    	memset(g,0,sizeof(g));
    	for(int s=0;s<x;s++) {
    		q[h=t=1]=0; g[s]=f[s];
    		for(int i=1;I<=m;i++) {
    			while(h<=t&&T[q[h]*x+s]<=i) h++; g[I]=max(f[q[h]*x+s]+w[x][i-q[h]-1],f[I]);
    			while(h<t&&T[q[t-1]*x+s]>=gettime(q[t],i,x,s)) t--;
    			T[q[t]*x+s]=gettime(q[t],i,x,s); q[++t]=i; T[I]=0x3f3f3f3f;
    		}
    	} for(int i=1;i<=m;i++) f[i]=max(g[i],f[i]);
    #undef I
    }
    signed main() {
    	scanf("%lld%lld",&n,&m);
    	for(int i=1,s,v;i<=n;i++) scanf("%lld%lld",&s,&v),w[s].push_back(v);
    	for(int i=1;i<=300;i++) {
    		if(!w[i].size()) continue ;
    		sort(w[i].begin(),w[i].end());
    		reverse(w[i].begin(),w[i].end());
    		for(int j=1;j<w[i].size();j++) w[i][j]+=w[i][j-1];
    		DP(i);
    	} for(int i=1;i<=m;i++) printf("%lld ",f[i]);
    }
    
  • 相关阅读:
    (OK) 从do_register_framebuffer开始的函数调用关系
    Linux内核基础--事件通知链(notifier chain)
    Java EE即将死去,毫无疑问!- Docker & 微服务 & DevOps
    GUI显示系统之SurfaceFlinger--- Gralloc与Framebuffer
    (OK) kernel create framebuffer device
    Android: 显示系统模块加载以及调用流程 HWComposer::loadFbHalModule() -> framebuffer_open()
    (OK) Android x86如何启动到图形界面&init.sh分析.md
    error: call to '__creat_missing_mode' declared with attribute error
    Android
    Android hwcomposer模块接口
  • 原文地址:https://www.cnblogs.com/ynyyyds/p/14209247.html
Copyright © 2011-2022 走看看