zoukankan      html  css  js  c++  java
  • [NAIPC2016]Jewel Thief(决策单调性+分治)

    [NAIPC2016]Jewel Thief(决策单调性+分治)

    题面

    原题提交地址(题目编号H)

    原题面下载地址

    (n)个物品,每个物品有一个体积(w_i)和价值(v_i),现在要求对(V in [1,m]),求出体积为(V)
    背包能够装下的最大价值

    (1 ≤ n ≤ 1000000; 1 ≤ m ≤ 100000; 1 ≤ w_i ≤ 300; 1 ≤ v_i ≤ 10^9)

    分析

    决策单调性发现

    注意到物品的体积很小,考虑按体积分类,选取同种体积的物品时,一定优先选择价值大的物品。

    (dp[i][j])为使用前i种体积的物品,体积为j的最大价值。类似多重背包的单调队列优化,将模i同余的所有位置拿出来重新标号(即下标看作1,2,3....x)。
    则有

    [dp[i][j]=max_{k=0}^j dp[i-1][k]+val(k,j) ]

    其中(w(k,j))表示第(i)种体积的物品中,最大的(j-k)个的价值和

    显然(val)满足四边形不等式。

    问题转化

    (A)为一个矩阵,(pos(j)=max({i|,forall p in [0,m],A[i][j]>A[p][j] })),即使得第(j)列第(i)行的值最大的(i)(如果有多个i相同,则取编号最大的)

    在原问题中,考虑第(i-1)层到第(i)层的转移 ,令(A[k][j]=egin{cases} dp[i-1][k]+val(k,j),k leq j \ -infty,k>jend{cases}),我们发现dp的转移实际上就是在求第(k)行第(j)列的最大值,其中(j)固定。那么(dp[i][j]=A[pos(j)][j])

    于是问题就转化为:已知一个((m+1) imes(m+1))大小的矩阵(A),其中每个元素的值均可以在(O(1))时间内查询。现
    要求对于(j in [0,m]),求出(A[pos(j)][j])

    分治求解

    对列[l,r]进行分治,维护当前可能成为(pos)的行([x,y]),令(mid=frac{l+r}{2}),暴力枚举所有可能的行求出(pos(mid)),分治递归操作([l,mid-1] [x,pos(mid)])以及([mid +1,r] [pos(mid),y])直至(l = r)(x = y)。容易发现这样的时间复杂度是(O(mlog m))

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    #define maxw 300
    #define maxn 1000000
    using namespace std;
    typedef long long ll;
    vector<ll>w[maxw+5];
    ll dp[2][maxn+5];
    int n,m;
    void divide(int l,int r,int x,int y,int now,int mod,int rest){
    	//列[l,r],行[x,y]; 
    	if(l>r) return;
    	int mid=(l+r)>>1,pos=mid;
    	dp[now^1][mid*mod+rest]=dp[now][mid*mod+rest];
    	for(int j=min(y,mid-1);j>=x;j--){//枚举可能成为pos(mid)的列,注意j<mid 
    		if(mid-j>(int)w[mod].size()) break;
    		if(dp[now][j*mod+rest]+w[mod][mid-j-1]>dp[now^1][mid*mod+rest]){
    			dp[now^1][mid*mod+rest]=dp[now][j*mod+rest]+w[mod][mid-j-1];
    			pos=j;
    		} 
    	}
    	divide(l,mid-1,x,pos,now,mod,rest);
    	divide(mid+1,r,pos,y,now,mod,rest);
    }
    
    inline int cmp(int x,int y){
    	return x>y;
    }
    int main(){
    	int x,y;
    	scanf("%d %d",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%d %d",&x,&y);
    		w[x].push_back(y);
    	} 
    	for(int i=1;i<=maxw;i++){
    		sort(w[i].begin(),w[i].end(),cmp);
    		for(int j=1;j<(int)w[i].size();j++) w[i][j]+=w[i][j-1]; 
    	}
    	int now=0;
    	for(int i=1;i<=300;i++){
    		if(w[i].size()){
    			for(int j=0;j<i;j++){
    				//将模i同余的所有位置拿出来
    				divide(0,(m-j)/i,0,(m-j)/i,now,i,j); 
    			}
    			for(int j=1;j<=m;j++){
    				dp[now^1][j]=max(dp[now^1][j],dp[now^1][j-1]);
    				//我们dp的子状态是体积<=j,而分治过程中是=j 
    			}
    			now^=1;
    		}
    	}
    	for(int i=1;i<=m;i++) printf("%I64d ",dp[now][i]);
    }
    
    
  • 相关阅读:
    cento7快速修改主机名和修改root密码
    [goolegke]nginxingress建立测试
    filebeat安装读取nginx json日志
    MySQL索引背后的数据结构及算法原理
    Lua脚本在redis分布式锁场景的运用
    Sentinel实现限流
    java架构技术流程图
    mybatis数据加解密处理方案
    vue 自定义代码片段
    node项目vue 自动化部署之pm2
  • 原文地址:https://www.cnblogs.com/birchtree/p/12060566.html
Copyright © 2011-2022 走看看