zoukankan      html  css  js  c++  java
  • Moo University

    题意:

    在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
    ",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
    ",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
     
  • 相关阅读:
    SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因
    微软BI 之SSIS 系列
    微软BI 之SSIS 系列
    微软BI 之SSIS 系列
    微软BI 之SSIS 系列
    微软BI 之SSIS 系列
    微软BI 之SSAS 系列
    微软BI 之SSRS 系列
    微软BI 之SSRS 系列
    配置 SQL Server Email 发送以及 Job 的 Notification通知功能
  • 原文地址:https://www.cnblogs.com/ibilllee/p/9221758.html
Copyright © 2011-2022 走看看