牛客网 【每日一题】6月11日题目精讲 背包
鏈接:
文章目錄
- 題目描述
- 題解:
- 代碼:
題目描述
Applese有1個容量為v的背包,有n個物品,每一個物品有一個價值ai,以及一個大小bi
然后他對此提出了自己的疑問,如果我不要裝的物品裝的價值最大,只是一定需要裝m個物品,要使得求出來的物品價值的中位數最大
Applese覺得這個題依然太菜,于是他把這個問題丟給了你 當物品數量為偶數時,中位數即中間兩個物品的價值的平均值
輸入描述:
第一行三個數v, n, m,分別代表背包容量,物品數量以及需要取出的物品數量 接下來n行,每行兩個數ai,bi,分別代表物品價值以及大小 n
≤ 1e5, 1 ≤ m ≤ n, ai ≤ 1e9, v ≤ 1e9, bi ≤ v
輸出描述:
僅一行,代表最大的中位數
示例1
輸入
輸出
8題解:
第一反應感覺是二分
m有奇數偶數兩種情況
當m是奇數時,左右分別取m/2個,最中間的就是我們要的答案
當m為偶數時,左邊取m/2-1個,右邊取m/2個,中位數為兩個數,就是當前第i個數和右邊第一個數(因為我們枚舉時只能選定一個,所以就通過選定第i個把第i+1也確定)
接下來詳細講講過程
x[i]表示物品最小體積的前綴和
y[]表示物品最小體積的后綴和
對于每一個位置,我們枚舉左右兩邊體積最小的m/2個數,(因為左右兩邊體積越小,給中間留的越多)
我們可以用優先隊列,從小到大依次放入,當背包容量不夠時,去掉最大值,依次這樣操作,留到最后的就是合理值
當求奇數時,枚舉每個位置,如果左右兩邊m/2個和中間的大小符合條件,則說明滿足條件。取最大的中間值
當求偶數時,最終答案是兩個數的平均值,我們枚舉這兩個中左邊的數,左邊取m/2-1個右邊取m/2個。我們的序列是經過排序的,右邊的第一個數取的越靠右
中位數就越大,但是越靠右他的物品總大小一定不會減少中位數就越大,但是越靠右他的物品總大小一定不會減少
可以發現,右邊選取物品的總大小是一個遞增的可以發現,右邊選取物品的總大小是一個遞增的
與此同時,他的價值也是遞增的,那么可以發現與此同時,他的價值也是遞增的,那么可以發現應該在大小符合的條件下盡量往右選,這就是明顯的二分啊應該在大小符合的條件下盡量往右選,這就是明顯的二分,直接二分右邊第一個的位置找到盡量靠右的合法位置即可
題解借鑒
代碼:
代碼是有問題的,但是我看了一陣子也沒找出來。。。
#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個數(含第i個)取m/2個物品其大小的和的最小值 //y表示后i個數(含第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){//偶數有兩個中位數,先確定一個,然后二分另外一個 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; }總結
以上是生活随笔為你收集整理的牛客网 【每日一题】6月11日题目精讲 背包的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 360浏览器5.0极速模式怎么开(360
- 下一篇: 牛客网 【每日一题】6月8日 [SCO