poj2010 Moo University - Financial Aid 枚举+优先队列/二分

题目链接:https://vjudge.net/problem/POJ-2010

题意:给出c个二元组(score,cost),要求选出n(奇数)个,使得选出的score中位数最大,且cost总和<=f,求这个最大中位数。

先对分数降序排序,再预处理从左边和右边开始最小的(n-1)/2的cost的和,l[i]表示从左边开始1到i,r[i]表示从右边开始n到i。具体实现使用优先队列,以l[i]为例,若a[i].cost<q1.top(),则更新l[i]的值为l[i-1]+a[i].cost-q1.top(),并更新q1的堆顶: q1.pop(),q1.push(a[i].cost);否则令l[i]=l[i-1],这样可以实现O(nlogn)预处理。最后枚举中位数,如果l[i-1]+a[i].cost+r[i+1]<=f直接输出a[i].score,循环结束无解就输出-1

 1 #include<iostream>
 2 #include<queue>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 const int maxn=1000+10;
 7 struct st{int sc,cost;}a[maxn];
 8 int l[maxn],r[maxn];
 9 int n,c,f,i;
10 priority_queue<int> q1,q2;
11 
12 bool cmp(st p,st q){ return p.sc>q.sc;}
13 
14 int main(){
15     std::ios::sync_with_stdio(false);
16     cin>>n>>c>>f;
17     for (i=1;i<=c;i++) cin>>a[i].sc>>a[i].cost;
18     sort(a+1,a+c+1,cmp);
19     for (i=1;i<=(n-1)/2;i++) {
20         l[(n-1)/2]+=a[i].cost;
21         q1.push(a[i].cost);
22     }
23     for (i=(n-1)/2+1;i<=c;i++){
24         if (a[i].cost<q1.top()){
25             l[i]=l[i-1]-q1.top()+a[i].cost;
26             q1.pop();q1.push(a[i].cost);
27         }
28         else l[i]=l[i-1];
29     }
30     for (i=c;i>=c-(n-1)/2+1;i--){
31         r[c-(n-1)/2+1]+=a[i].cost;
32         q2.push(a[i].cost);
33     } 
34     for (i=c-(n-1)/2;i>=1;i--){
35         if (a[i].cost<q2.top()){
36             r[i]=r[i+1]-q2.top()+a[i].cost;
37             q2.pop();q2.push(a[i].cost);
38         }
39         else r[i]=r[i+1];
40     }
41     for (i=(n-1)/2+1;i<=c-(n-1)/2;i++)
42       if (l[i-1]+a[i].cost+r[i+1]<=f){
43           cout<<a[i].sc<<endl;
44           return 0;      
45       }
46     cout<<-1<<endl;
47     return 0;
48 }
poj2010

应该还有一种二分的做法,待补(咕咕咕)

猜你喜欢

转载自www.cnblogs.com/edmunds/p/12981081.html