题目描述
蛤布斯有nn个物品和一个大小为mm的背包,每个物品有大小和价值,它希望你帮它求出背包里最多能放下多少价值的物品。
输入数据
第一行两个整数 n,mn,m。
接下来 nn 行每行两个整数 xi,wixi,wi,表示第ii个物品的大小和价值。
输出数据
一行一个整数表示最大价值。
样例输入
5 100
95 80
4 18
3 11
99 100
2 10
样例输出
101
数据范围
对于20%20%的数据,xi≤1500xi≤1500。
对于30%30%的数据,wi≤1500wi≤1500。
对于100%100%的数据,n≤40,0≤m≤1018,0≤xi,wi≤1016n≤40,0≤m≤1018,0≤xi,wi≤1016。
题目分析
整体二分啊,我先打了个DP,结果很悲壮。因为题目的数据太大了,m到long long极限了,所以用整体二分。整体二分是什么呢?我们枚举左半边,并排序。然后对右边进行搜索。这就是折半搜索。然后我们上代码。20分做法就是直接DP滚动数组。
#include<bits/stdc++.h> #define int long long using namespace std; struct aa{int v,w; friend bool operator<(aa a,aa b){ return a.v!=b.v?a.v<b.v:a.w>b.w; }}b[1<<21]; int n,cnt,tot,n2,m,v[50],w[50],ans; inline int search(int x){ int l=1,r=tot,mid; while(l<r){ if(b[mid=(l+r)>>1].v>x)r=mid; else l=mid+1; }return b[l-1].w; }void dfs1(int now,int sum_v ,int sum_w){ if(now>n2){b[++cnt]=(aa){sum_v,sum_w};return;} dfs1(now+1,sum_v,sum_w); if(sum_v+v[now]<=m) dfs1(now+1,sum_v+v[now],sum_w+w[now]); }void dfs2(int now,int sum_v,int sum_w){ if(now>n){ ans=max(ans,sum_w+=search(m-sum_v)); return; }dfs2(now+1,sum_v,sum_w); if(sum_v+v[now]<=m) dfs2(now+1,sum_v+v[now],sum_w+w[now]); }signed main(){freopen("pack.in","r",stdin),freopen("pack.out","w",stdout); cin>>n>>m; for(int i=1;i<=n;i++) cin>>v[i]>>w[i]; n2=n>>1,dfs1(1,0,0),sort(b+1,b+cnt+1); for(int i=2;i<=cnt;i++) if(b[i].v>b[i-1].v) b[++tot]=b[i]; for(int i=2;i<=tot;i++) b[i].w=max(b[i].w,b[i-1].w); dfs2(n2+1,0,0),cout<<ans; }
代码说明
我家小姐姐没什么信心,我也没什么期望了。到时候生物信息两开花。说多了都是泪,最近没什么心情更新我们的情感生活了。