這是一道利用優先隊列預處理的一道題.
網上有一些二分的題解,但是是錯的.
對於每個中位數,我們對於其前面的n/2個數,並用優先隊列預處理.size大於n/2時pop掉學費最貴的.
後n/2也是這麼預處理的
最後只要到過來找第一個成立的即可,否則就是-1
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
const int maxn = 1e5+30;
const int inf = 0x3f3f3f3f;
using namespace std;
int n,c,f;
int half;
pair<int, int>cow[maxn];
int lower[maxn], upper[maxn];
void init(int st, int ed, int *a){
int total = 0;
priority_queue<int>q;
bool flag = st<ed;
if(flag){
for(int i = st; i < ed; i++){
a[i] = (q.size() == half? total:inf);
q.push(cow[i].second);
total += cow[i].second;
if(q.size() > half){
total -= q.top(); q.pop();
}
}
} else {
for(int i = st; i >= ed; i--){
a[i] = (q.size() == half? total:inf);
q.push(cow[i].second);
total += cow[i].second;
if(q.size() > half){
total -= q.top(); q.pop();
}
}
}
}
int main() {
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
while(~scanf("%d%d%d",&n,&c,&f)) {
half = n/2;
for(int i = 0; i < c; i++) {
scanf("%d%d",&cow[i].first, &cow[i].second);
/*
if(cow[i].second > f) {
i --;
c --;
}
*/
}
sort(cow, cow+c);
//預處理
init(0, c, lower);
init(c-1, 0, upper);
//
int ans = -1;
for(int i = c-1; i >= 0; i--) {
if(lower[i] + cow[i].second + upper[i] <= f) {
ans = cow[i].first;
break;
}
}
cout << ans << endl;
}
return 0;
}
二分代碼:
錯在不能保證mid左右兩個區間至少有一個區間內是全滿足的,但是如果我們mid就不成立,那麼下面的區間縮小根本不能進行.而數據竟然弱到可以wa掉二分的.
數據:
3 5 17
1 2
7 2
8 16
9 13
11 15
ans = 7
以下爲錯誤代碼:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#define ll long long
const int maxn = 1e5+30;
using namespace std;
int n,c,f;
int ans;
struct cow{
int score, aid, rak;
cow() {}
cow(int score, int aid): score(score), aid(aid){}
}cows[maxn],cowa[maxn];
bool cmp_score(cow a, cow b){
if(a.score == b.score)return a.aid < b.aid;
return a.score < b.score;
}
bool cmp_aid(cow a, cow b){
if(a.aid == b.aid)return a.score < b.score;
return a.aid < b.aid;
}
int main () {
ios::sync_with_stdio(false);cout.tie(0);
while(~scanf("%d%d%d",&n,&c,&f)){
for(int i = 0; i < c; i++){
scanf("%d%d",&cows[i].score, &cows[i].aid);
}
sort(cows, cows+c, cmp_score);
for(int i = 0; i < c; i++){
cows[i].rak = i;
}
memcpy(cowa, cows, sizeof cows);
sort(cowa, cowa+c, cmp_aid);
int l = 0, r = c, mid;
ans = -1;
//二分中間值
while(r>l+1){
mid = (l+r)>>1;
int left = 0, right = 0, total = cows[mid].aid;
//貪心的選取
for(int i = 0; i < c ; i++){
if((cowa[i].rak < mid) && (total + cowa[i].aid <= f) && (left < n/2)){
total += cowa[i].aid;
left++;
}else if((cowa[i].rak > mid) && (total + cowa[i].aid <= f) && (right < n/2)){
total += cowa[i].aid;
right++;
}
}
if((left < n/2) && (right < n/2)){
ans = -1;break;
}else if(left < n/2){
l = mid;
}else if(right < n/2){
r = mid;
}else {
ans = cows[mid].score;
l = mid;
}
}
cout << ans << endl;
}
return 0;
}
優先隊列是由大頂堆實現的.
下面是堆排序的代碼.
首先做了一個自下向上的建堆處理
保證節點比其兒子的值更大.
然後就每次把堆頂的數字拿出來與最後的數字兌換,在自上而下的調整.最終實現排序
#include<cstdio>
void maxHeap(int *a,int n,int i)
{
//left、right、largest分別指向
//左孩子、右孩子、{a[i],a[left]}中最大的一個
int left,right,largest;
largest=left=2*i;
if(left>n)
return;
right=2*i+1;
if(right<=n && a[right]>a[left]){
largest=right;
}
if(a[i]<a[largest]){//根結點的值不是最大時,交換a[i],a[largest]
a[i]=a[i]+a[largest];
a[largest]=a[i]-a[largest];
a[i]=a[i]-a[largest];
//自上而下調整堆
maxHeap(a,n,largest);
}
}
//建堆
void creatHeap(int *a,int n)
{
int i;
//自下而上調整堆
for(i=n/2;i>=1;i--)
maxHeap(a,n,i);
}
//堆排序
void heapSort(int *a,int n)
{
int i;
creatHeap(a,n);//建堆
for(i=n;i>=2;i--){
//堆頂記錄和最後一個記錄交換
a[1]=a[1]+a[i];
a[i]=a[1]-a[i];
a[1]=a[1]-a[i];
//堆中記錄個數減少一個,篩選法調整堆
maxHeap(a,i-1,1);
}
}
int main()
{
int i;
int a[7]={0, 5,1,7,9,8,2};//不考慮a[0]
heapSort(a,6);
for(i=1;i<=6;i++)
printf("%-4d",a[i]);
printf("\n");
}
如果是node,不能按下面這麼寫.
priority_queue<Node, vector<Node>, greater<Node> >;
要把greater改成下面這樣的
struct cmp{
bool operator() ( Node a, Node b ){
if( a.x== b.x ) return a.y> b.y;
return a.x> b.x; }
};