题意:
一共C个学生,学校要录N(奇数)个,每个学生的分数和需要的aid给出,学校最多能提供F资金,求录取的学生中分数中位数最大。
题解:
方法1:对所有的学生按照分数进行从小到大排序,左边从第N/2+1个学生开始,到第C-N/2个学生结束,算出每个学生以他的分数为中位数,左边需要的最小总aid,需要用到优先队列!
同样地,对右边也进行计算,以每个学生自身为中位数,右边需要的最小总aid。
最后从右往左扫描,算出以每个学生为中位数,左右需要的总aid,<=F即可!
方法2:二分。对于每个mid看是否满足左右两边的score=N/2,并且aid<=F。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<string>
#include<cstring>
using namespace std;
struct node
{
int score,aid,left,right;
};
bool cmp(struct node x1,struct node x2)
{
return x1.score<x2.score;
}
struct node a[100000+5];
int main()
{ memset(a,0,sizeof(a));
int N,C,F;
cin>>N>>C>>F;
for(int i=1; i<=C; i++)
scanf("%d%d",&a[i].score,&a[i].aid);
sort(a+1,a+C+1,cmp);
priority_queue<int>q;
int sum=0;
if(N>1)
{ //前N/2个肯定不能当中位数
for(int i=1; i<=N/2; i++)
{
q.push(a[i].aid);
sum+=a[i].aid;
}
//从N/2+1开始,计算分数比他小的N/2个最少需要多少aid
for(int i=N/2+1; i<=C-N/2; i++)
{
a[i].left=sum;
if(a[i].aid<q.top())
{
sum=sum-q.top()+a[i].aid;
q.pop();
q.push(a[i].aid);
}
}
while(q.size())q.pop();
sum=0;
//右边同理;
for(int i=C; i>C-N/2; i--)
{
q.push(a[i].aid);
sum+=a[i].aid;
}
for(int i=C-N/2; i>=N/2+1; i--)
{
a[i].right=sum;
if(a[i].aid<q.top())
{
sum=sum-q.top()+a[i].aid;
q.pop();
q.push(a[i].aid);
}
}
}
int ans=-1;
for(int i=C-N/2; i>N/2; i--)
{
int total=a[i].left+a[i].right+a[i].aid;
if(total<=F)
{
ans=a[i].score;
break;
}
}
cout<<ans<<endl;
}
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<string>
#include<cstring>
using namespace std;
const int maxn=100000+5;
struct node{int rank_by_score,score,aid;};
node cow_score[maxn],cow_aid[maxn];
bool less_by_score(struct node a,struct node b)
{
return a.score<b.score;
}
bool less_by_aid(struct node a,struct node b)
{
return a.aid<b.aid;
}
int main()
{
int N,C,F;
cin>>N>>C>>F;
for(int i=1;i<=C;i++)
scanf("%d%d",&cow_score[i].score,&cow_score[i].aid);
sort(cow_score+1,cow_score+1+C,less_by_score);
for(int i=1;i<=C;i++)
cow_score[i].rank_by_score=i;
memcpy(cow_aid,cow_score,sizeof(node)*(C+1));
sort(cow_aid+1,cow_aid+C+1,less_by_aid);
int lb=1,ub=C,ans=-1;
while(ub-lb>1)
{
int mid=(lb+ub)>>1;
int left=0,right=0,total_aid=cow_score[mid].aid;
for(int i=1;i<=C;i++)//按照aid从小到大 扫描
{ //每次去找mid 左右两边 aid总和最小的。如果能找到符合条件的,则left,right最后应该都为N/2;
//如果扫描一遍 left,right 都小于N/2,那么就是没有符合题意的解了。
if(cow_aid[i].rank_by_score<mid && total_aid+cow_aid[i].aid<=F && left< N/2 )
{
total_aid+=cow_aid[i].aid;
left++;
}
else if(cow_aid[i].rank_by_score>mid && total_aid+cow_aid[i].aid<=F && right< N/2 )
{
total_aid+=cow_aid[i].aid;
right++;
}
}
if(left<N/2 && right< N/2)//从小的aid开始选,都选不够N个
{
ans=-1;
break;
}
else if(left < N/2)//放大
lb=mid;
else if(right<N/2)//缩小
ub=mid;
else
{
ans=cow_score[mid].score;
lb=mid;//求最大
}
}
cout<<ans<<endl;
}