zoukankan      html  css  js  c++  java
  • [HNOI2007]梦幻岛宝珠

    题目

    题意简洁明了,就是做一个01背包,但是背包的容量(W)非常大,并且给出的物品的体积都能表示成(a imes 2^b,aleq 10,bleq 30)

    显然这个(a)拿来做背包的体积非常合适,于是我们按照(b)分类,设(dp_{i,j})表示只使用(a imes 2^i)形式的物品,凑出(j imes 2^i)体积的最大价值

    其实就是对每一种(b)单拎出来做一个01背包

    考虑合并掉(dp)数组,设(f_{i,j})表示合并出一个形如(j imes2^i)并且后(i-1)位都不超过(W)(i-1)位的最大价值

    不难发现我们的答案就是(max(f_{log w,0},f_{log w,1}))

    合并的时候也大力转移,我们枚举一下(i-1)位给(i)进多少位,则有

    [f_{i,j}=max_{k=0}f_{i-1,2 imes k+w_{i-1}}+dp_{i,k-j} ]

    代码

    #include<bits/stdc++.h>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    int a[31][105],b[31][105];
    int dp[31][1005],f[31][2005];
    int sum[31],cnt[31],n,m,bit[31],tot,S[31];
    int main() {
    	while(1) {
    		scanf("%d%d",&n,&m);
    		if(n==-1&&m==-1) return 0;tot=0;
    		for(re int i=0;i<=30;++i) cnt[i]=0,S[i]=0;
    		memset(dp,0,sizeof(dp));memset(f,0,sizeof(f));
    		for(re int w,v,i=1;i<=n;i++) {
    			w=read(),v=read();
    			for(re int j=0;j<=30;++j) {
    				if(w/(1<<j)<=10) {
    					a[j][++cnt[j]]=w/(1<<j),b[j][cnt[j]]=v;
    					S[j]+=a[j][cnt[j]];
    					break;
    				}
    			}
    		}
    		for(re int i=0;i<=30;++i)
    			for(re int j=1;j<=cnt[i];++j)
    				for(re int k=S[i];k>=a[i][j];--k)
    					dp[i][k]=max(dp[i][k],dp[i][k-a[i][j]]+b[i][j]);
    		sum[0]=S[0];
    		for(re int i=1;i<=30;++i) sum[i]=sum[i-1]/2+1+S[i];
    		for(re int i=0;i<=S[0];++i) f[0][i]=dp[0][i];
    		while(m) bit[tot++]=(m&1),m>>=1;tot--;
    		for(re int i=1;i<=tot;++i) 
    			for(re int j=0;j<=sum[i];++j)
    				for(re int k=0;k<=j&&k<=S[i];++k) {
    					if(2*(j-k)+bit[i-1]<=sum[i-1]) 
    						f[i][j]=max(f[i][j],dp[i][k]+f[i-1][2*(j-k)+bit[i-1]]);
    					else f[i][j]=max(f[i][j],dp[i][k]+f[i-1][sum[i-1]]);
    				}
    		int ans=max(f[tot][0],f[tot][1]);
    		for(re int i=0;i<tot;++i) 
    			ans=max(ans,max(f[i][0],f[i][1]));
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    PowerDNS简单教程(4):优化篇
    PowerDNS简单教程(3):管理篇
    PowerDNS简单教程(2):功能篇
    PowerDNS简单教程(1):安装篇
    【转】Linux vmstat命令实战详解
    折腾apt源的时候发生的错误
    Ubuntu14.04安装PowerDNS踩坑实录
    Ubuntu14.04.3,apt-get出现dpkg: error processing package xxx (--configure)和cups-daemon错误的解决方案
    Python解析配置文件模块:ConfigPhaser
    SSH异常处理(一)
  • 原文地址:https://www.cnblogs.com/asuldb/p/11603791.html
Copyright © 2011-2022 走看看