• 梦幻岛宝珠题解


    圆题链接

    01背包冲鸭!!!

    好吧他死了,考虑每一个物品体积都为(b*2^a)尝试进制优化
    首先设背包大小为(m)
    (f_{i,j})为背包大小最高位为(j*2^i)时最大价值
    也就是说,设现在考虑的物品编号为(k),则背包大小为(j*2^i)+(()(w_k)&(((1<<i)-1))))
    原来我们是枚举整个背包大小,而现在我们不再考虑低于第(i)位的确切数值
    比如当(w_k=1001)(i=5,j=1),背包大小为(11001)(除了(i),以上均为二进制)
    转移则为(f_{i,j}=max(f_{i,j},f_{i,j-d}+f{i-1,2*d|((m>>(i-1))-1)}))
    就是说考虑从(i-1)处转移过来(2^i*d)大小的体积,由于(i)减了(1)(d)相应要乘(2)
    就是(f_{i-1,2*d}),考虑背包自身上限,还可以加上一个(2*d+((m>>(i-1))-1)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    using namespace std;
    const ll N=1005;
    ll n,m,f[35][N],a[N],b[N],top;
    
    int main(){
    	scanf("%lld%lld",&n,&m);
    	while(n!=-1&&m!=-1){
    		top=0;
    		memset(f,0,sizeof f);
    		for(ll i=1;i<=n;i++){
    			ll cnt=0,x;
    			scanf("%lld%lld",&a[i],&b[i]),x=a[i];
    			while(x%2==0){x/=2,cnt++;}
    			for(ll j=1000;j>=x;j--){
    				f[cnt][j]=max(f[cnt][j],f[cnt][j-x]+b[i]);
    			}
    		}
    		for(ll i=m;i>0;i/=2)top++;
    		top--;
    		for(ll i=1;i<=top;i++){
    			for(ll j=1000;j>=0;j--){
    				for(ll k=0;k<=j;k++){
    					f[i][j]=max(f[i][j],f[i][j-k]+f[i-1][min(1000*1ll,(k*2)|((m>>(i-1))&1))]);
    				}
    			}
    		} 
    		printf("%lld
    ",f[top][1]);
    		scanf("%lld%lld",&n,&m); 
    	}
    }
    

    代码比较憨,请见谅

  • 相关阅读:
    关于相机权限
    JDBC插入中文出现乱码问题
    记一次Java代码的部署
    Java-final关键字
    Java枚举使用详解
    临时表
    Oracle 11g 建表 表名大小写问题
    ORA-04021等待锁定对象时超时
    Oracle 查询时间差几天
    NVL()
  • 原文地址:https://www.cnblogs.com/caijiLYC/p/13833057.html
Copyright © 2020-2023  润新知