Moo University - Financial Aid [POJ2010] [堆]

题意:

在C头牛里选N头牛,每头牛需要花掉一定经费ai才能得到一定得bi分,在不超过经费F的情况下,使得N头牛的得分中位数最大。(1 <= N <= 19,999,奇数) (N <= C <= 100,000)(0 <= F <= 2,000,000,000)

输入:(N,C,F;ai,bi)

3 5 70
30 25
50 21
20 20
5 18
35 30
输出:
   35
分析:
最朴素的办法:按分数从小到大排列,枚举原点,从右到左扫,区间为[(m+1)/2,n-(m+1)/2],计算左边最小和和右边最小和,判断是否是满足条件,满足即输出。
显然这种n2的办法是不行的。
我们要减复杂度,就要在枚举原点的同时维护左右两边最小和,如何维护?
方法一(较复杂,但是是一个解决问题的想法):
针对右边,我们的需求是:不断加入值,求前k小的和。我们建立一个大根堆,并在开始的时候记录一个sumR,每加入一个点,如果小于大根堆顶,便更新sumR,弹出堆顶,压入新点。
针对左边,我们的需求是:不断删去值,求前k小的和这个方法就困难在这里,我们在区间[1,(2n-m-1)/2]新建立一个数组new,按花销从小到大排序,同样时原位置小的在前,同时记录该点是否要去除(usd)。什么意思呢?我们最开始在原数组统计的和sumL=sum(1->(m-1)/2),并在(m-1)/2处设立一个指针p。在原数组删去一个数的时候,如果在new对应的位置在p右边则不用管,标记usd=1。如果在p位置或p位置的左边,就在sumL删除这个数,p向右移至第一个usd没被标记的地方,sumL加入这个新数。
方法二:
我们发现不断删去值,求前k小的和要比不断加入值,求前k小的和更加困难,那我们就提前从左向右扫一边,那么针对左边,就是和右边一样的需求了(不断加入值,求前k小的和)。
这道题还是费了我一点脑子的...
 
代码:
 1 #include<set>
 2 #include<map>
 3 #include<queue>
 4 #include<stack>
 5 #include<cmath>
 6 #include<cstdio>
 7 #include<cstring>
 8 #include<iostream>
 9 #include<algorithm>
10 #define RG register int
11 #define rep(i,a,b)    for(RG i=a;i<=b;++i)
12 #define per(i,a,b)    for(RG i=a;i>=b;--i)
13 #define ll long long
14 #define inf (1<<29)
15 #define maxn 100005
16 using namespace std;
17 int n,m,F,L,R,rt;
18 int sL,sR;
19 int po[maxn];
20 struct D{
21     int cost,sco;
22     inline int operator < (const D &tmp)const{
23         return sco<tmp.sco;
24     }
25 }a[maxn];
26 struct Dat{
27     int val,id,usd;
28     inline int operator < (const Dat &tmp)const{
29         return (val==tmp.val)?id<tmp.id:val<tmp.val;
30     }
31 }b[maxn];
32 priority_queue<int> que;
33 inline int read()
34 {
35     int x=0,f=1;char c=getchar();
36     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
37     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
38     return x*f;
39 }
40 
41 void work()
42 {
43     L=(m+1)/2,R=n-(m-1)/2;
44     
45     int end=(2*n-m+3)/2;
46     per(i,n,end)    que.push(a[i].cost),sR+=a[i].cost;
47     
48     
49     end=(2*n-m-1)/2,rt=(m-1)/2;
50     rep(i,1,end)    b[i].val=a[i].cost,b[i].id=i;
51     sort(b+1,b+1+end);
52     rep(i,1,end)    po[b[i].id]=i;
53     rep(i,1,rt)        sL+=b[i].val;
54     
55     end=(2*n-m+3)/2;
56     per(O,R,L)
57     {
58         if(sL+sR+a[O].cost<=F)    {printf("%d\n",a[O].sco);return;}
59         
60         if(a[O].cost<que.top())    sR-=que.top()-a[O].cost,que.pop(),que.push(a[O].cost);
61         
62         b[po[O-1]].usd=1;
63         if(po[O-1]<=rt)
64         {
65             while(b[rt].usd&&rt<=end)    rt++;
66             if(rt==(2*n-m+5)/2)    {puts("-1");return;}
67             sL+=b[rt].val-a[O-1].cost;
68         }
69     }
70     puts("-1");return;
71 }
72 
73 void dif()
74 {
75     per(i,n,1)
76         if(a[i].cost<=F){printf("%d\n",a[i].sco);return;}
77     exit(0);
78     
79 }
80 
81 int main()
82 {
83     m=read(),n=read(),F=read();
84     rep(i,1,n)    a[i].sco=read(),a[i].cost=read();
85     sort(a+1,a+1+n);
86     L=(m+1)/2,R=n-(m-1)/2;
87     if(m==1)    dif();
88     else         work();
89     return 0;
90 }
View Code
 
posted @ 2018-06-25 15:28  iBilllee  阅读(181)  评论(0编辑  收藏  举报