牛客网 【每日一题】6月11日题目精讲 背包
鏈接:
文章目錄
- 題目描述
- 題解:
- 代碼:
題目描述
Applese有1個容量為v的背包,有n個物品,每一個物品有一個價值ai,以及一個大小bi
然后他對此提出了自己的疑問,如果我不要裝的物品裝的價值最大,只是一定需要裝m個物品,要使得求出來的物品價值的中位數(shù)最大
Applese覺得這個題依然太菜,于是他把這個問題丟給了你 當(dāng)物品數(shù)量為偶數(shù)時,中位數(shù)即中間兩個物品的價值的平均值
輸入描述:
第一行三個數(shù)v, n, m,分別代表背包容量,物品數(shù)量以及需要取出的物品數(shù)量 接下來n行,每行兩個數(shù)ai,bi,分別代表物品價值以及大小 n
≤ 1e5, 1 ≤ m ≤ n, ai ≤ 1e9, v ≤ 1e9, bi ≤ v
輸出描述:
僅一行,代表最大的中位數(shù)
示例1
輸入
輸出
8題解:
第一反應(yīng)感覺是二分
m有奇數(shù)偶數(shù)兩種情況
當(dāng)m是奇數(shù)時,左右分別取m/2個,最中間的就是我們要的答案
當(dāng)m為偶數(shù)時,左邊取m/2-1個,右邊取m/2個,中位數(shù)為兩個數(shù),就是當(dāng)前第i個數(shù)和右邊第一個數(shù)(因為我們枚舉時只能選定一個,所以就通過選定第i個把第i+1也確定)
接下來詳細(xì)講講過程
x[i]表示物品最小體積的前綴和
y[]表示物品最小體積的后綴和
對于每一個位置,我們枚舉左右兩邊體積最小的m/2個數(shù),(因為左右兩邊體積越小,給中間留的越多)
我們可以用優(yōu)先隊列,從小到大依次放入,當(dāng)背包容量不夠時,去掉最大值,依次這樣操作,留到最后的就是合理值
當(dāng)求奇數(shù)時,枚舉每個位置,如果左右兩邊m/2個和中間的大小符合條件,則說明滿足條件。取最大的中間值
當(dāng)求偶數(shù)時,最終答案是兩個數(shù)的平均值,我們枚舉這兩個中左邊的數(shù),左邊取m/2-1個右邊取m/2個。我們的序列是經(jīng)過排序的,右邊的第一個數(shù)取的越靠右
中位數(shù)就越大,但是越靠右他的物品總大小一定不會減少中位數(shù)就越大,但是越靠右他的物品總大小一定不會減少
可以發(fā)現(xiàn),右邊選取物品的總大小是一個遞增的可以發(fā)現(xiàn),右邊選取物品的總大小是一個遞增的
與此同時,他的價值也是遞增的,那么可以發(fā)現(xiàn)與此同時,他的價值也是遞增的,那么可以發(fā)現(xiàn)應(yīng)該在大小符合的條件下盡量往右選,這就是明顯的二分啊應(yīng)該在大小符合的條件下盡量往右選,這就是明顯的二分,直接二分右邊第一個的位置找到盡量靠右的合法位置即可
題解借鑒
代碼:
代碼是有問題的,但是我看了一陣子也沒找出來。。。
#include<bits/stdc++.h> const int maxn= 1e5+2; typedef long long ll; using namespace std; struct node{ll a,b,id; }w[maxn]; ll x[maxn],y[maxn]; //x表示前i個數(shù)(含第i個)取m/2個物品其大小的和的最小值 //y表示后i個數(shù)(含第i個)取m/2個物品其大小的和的最小值 bool cmp1(node a1,node b1) {return a1.a<b1.a;//按照 價值排序 } priority_queue<int>q; long long int v,n,m; //v n m ll solve1(){ll sum=0;for(int i=m+1;i<=n-m;i++){if(x[i-1]+y[i+1]+w[i].b<=v)sum=w[i].a;//枚舉中間值,再上左右兩邊,看看有沒有超過背包容量 return sum;} } ll solve2(){ll sum=0;for(int i=m;i<=n-m;i++){int l=i+1;int r=n-m+1;while(l<=r){//偶數(shù)有兩個中位數(shù),先確定一個,然后二分另外一個 int mid=(r+l)>>1;if(x[i-1]+y[mid]+w[i].b<=v)l=mid+1;//如果沒超過背包的體積,說明中間值還可以更大 else r=mid-1;//否則更小 }if(r>i)sum=max(sum,w[i].a+w[r].a);//中間兩個值和的最大值 }return sum/2; } int main() {cin>>v>>n>>m;for(int i=1;i<=n;i++){cin>>w[i].a>>w[i].b;}sort(w+1,w+1+n,cmp1);int z=m&1;m>>=1;for(int i=1;i<=n;i++){q.push(w[i].b);x[i]=x[i-1]+w[i].b;if(q.size()>m-1+z){x[i]-=q.top();q.pop();}}while(!q.empty())q.pop();for(int i=n;i;i--){q.push(w[i].b);y[i]=y[i+1]+w[i].b;if(q.size()>m){y[i]-=q.top();q.pop();}}if(z){cout<<solve1();}else {cout<<solve2();}return 0; }總結(jié)
以上是生活随笔為你收集整理的牛客网 【每日一题】6月11日题目精讲 背包的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 360浏览器5.0极速模式怎么开(360
- 下一篇: 牛客网 【每日一题】6月8日 [SCO