题目大意:
C个奶牛,两个属性:分数和金额
在金额总和不超过F的情况下,选出N个奶牛,使得N个奶牛的分数的中位数尽可能大
玄学ac……数据可能比较弱吧,这个思路有点问题T_T
思路:
因为要取得最大的中位数,所以有N/2个分数对结果没影响,这部分尽可能取钱最少的,先按金额排序,贪心的取最小的N/2个。然后剩下的按分数从大到小排序,维护一个N/2+1的区间,若金额不够就取出金额最大的,放入下一个,直到金额够取,最后全部排序输出中位数。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=100000;
const int maxc=20000;
int n,f,c,a[maxn],b[maxn],r[maxn]; //a:分数,b:钱
bool vis[maxn]; //标记第一次取过的奶牛
vector<int> ans; //存最后取的所有奶牛
struct node //优先队列节点
{
int pos,s,m;
};
struct cmp //优先队列排序,优先出钱最多的
{
bool operator()(node a,node b)
{
return a.m<b.m;
}
};
priority_queue<node,vector<node>,cmp> q;
bool cmp1(int x,int y) //按钱数间接排序
{
return b[x]<b[y];
}
bool cmp2(int x,int y) //按分数间接排序
{
return a[x]>a[y];
}
int main()
{
while(~scanf("%d%d%d",&n,&c,&f))
{
memset(vis,0,sizeof(vis));
for(int i=0;i<c;i++)
{
scanf("%d%d",&a[i],&b[i]);
}
for(int i=0;i<=c;i++) r[i]=i;
sort(r,r+c,cmp1);
int res=n>>1;
for(int i=0;i<res;i++) //取N/2个
{
int e=r[i];
f-=b[e];
vis[e]=true;
ans.push_back(a[e]);
}
res=n-res;
for(int i=0;i<=c;i++) r[i]=i;
sort(r,r+c,cmp2);
int p,cnt=0,sum=0;
for(p=0;p<c;p++) //取N/2+1个
{
int e=r[p];
if(!vis[e])
{
cnt++; vis[e]=true;
node temp;
temp.m=b[e]; temp.pos=e; temp.s=a[e];
sum+=b[e];
q.push(temp);
}
if(cnt==res) break;
}
while(sum>f) //维护到钱够取的情况
{
p++;
if(p==c) break;
int e=r[p];
node temp1=q.top();
if(temp1.m>b[e]&&!vis[e])
{
q.pop();
node temp2;
temp2.m=b[e]; temp2.pos=e; temp2.s=a[e];
q.push(temp2);
sum-=temp1.m;
sum+=temp2.m;
}
}
if(sum<=f)
{
while(!q.empty())
{
node temp;
temp=q.top(); q.pop();
ans.push_back(temp.s);
}
sort(ans.begin(),ans.end());
printf("%d\n",ans[n/2]);
}
else printf("-1\n");
}
}
后来想了想每次弹出钱数最高的可能不太合理,可能弹出一个钱数不是最大的再取一个也能使钱数满足条件且钱数最大那个恰好是中位数最大那个。
想了组数据
5 6 21
9 1
8 1
7 9
6 7
5 4
4 6
果然答案不合适:)