• [优先队列][贪心] Bzoj P4977 跳伞求生


    Description

    小Q最近沉迷于《跳伞求生》游戏。他组建了一支由n名玩家(包括他自己)组成的战队,编号依次为1到n。这个游
    戏中,每局游戏开始时,所有玩家都会从飞机上跳伞,选择一个目的地降落,跳伞和降落的时间有早有晚。在某局
    游戏降落前,他们在空中观察发现地面上一共有m间房子,编号依次为1到m。其中每间房子恰好有一名敌人早于他
    们到达。小Q战队的第i名玩家拥有a_i发子弹,地面上第i间房子里的敌人拥有b_i发子弹,消灭他可以获得c_i点积
    分。每名玩家必须且只能选择一间房子降落,然后去消灭里面的敌人。若第i名玩家选择了第j间房子,如果a_i>b_
    j,那么他就可以消灭该敌人,获得a_i-b_j+c_j的团队奖励积分,否则他会被敌人消灭。为了防止团灭,小Q不允
    许多名玩家选择同一间房子,因此如果某位玩家毫无利用价值,你可以选择让他退出游戏。因为房子之间的距离过
    长,你可以认为每名玩家在降落之后不能再去消灭其它房间里的敌人。作为小Q战队的指挥,请制定一套最优的降
    落方案,使得最后获得的团队奖励总积分最大

    Input

    第一行包含两个正整数n,m(1<=n,m<=100000),分别表示战队的玩家数和地面上的房间数。
    第二行包含n个正整数a_1,a_2,...,a_n(1<=a_i<=100000),分别表示每个玩家的子弹数。
    接下来m行,每行两个正整数b_i,c_i(1<=b_i,c_i<=100000),分别表示每个敌人的子弹数和奖励积分。

    Output

    输出一行一个整数,即最后获得的团队奖励总积分的最大值。

    Sample Input

    3 3
    4 4 4
    2 3
    1 3
    5 3

    Sample Output

    11

    题解

    • 先考虑贪心
    • 将每个人所拥有的子弹数从小到大排序,然后开一个优先队列维护ci-bi
    • 那么对于一个队友,如果他可以干掉一个人,那么就把这个人干掉然后把贡献加上
    • 对于敌人ci-bi小于0,也就是打死这个敌人木有贡献,那么可舍弃掉一些敌人
    • 按照上面的方法可以跑出一个解,之后要做的是
    • 把用到的队友和干掉的敌人存下来,然后每次删掉a最小的队友和c-b最小的敌人
    • 得到另一个解(这样删仍然合法,因为队友从小到大删不会产生不合法配对),并更新答案 

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <queue>
     4 #include <algorithm>
     5 #define N 200010
     6 #define ll long long
     7 using namespace std;
     8 int n,m,l,r,d[N];
     9 ll ans,sum;
    10 priority_queue <int> Q;
    11 priority_queue <int,vector<int>,greater<int> > E;
    12 struct edge { int x,y,k; }a[N];
    13 bool cmp(edge a,edge b) { return a.x<b.x||a.x==b.x&&a.k<b.k; }
    14 int main()
    15 {
    16     scanf("%d%d",&n,&m);
    17     for (int i=1;i<=n;i++) scanf("%d",&a[i].x),a[i].k=0;
    18     for (int i=1;i<=m;i++) n++,scanf("%d%d",&a[n].x,&a[n].y),a[n].y-=a[n].x,a[n].k=1;
    19     sort(a+1,a+n+1,cmp),l=1;
    20     for (int i=1;i<=n;i++)
    21     {
    22         if (a[i].k==1) Q.push(a[i].y);
    23         else 
    24         {
    25             if (Q.empty())
    26             {
    27                 if (l<=r) sum+=a[i].x-d[l++],d[++r]=a[i].x;
    28             }
    29             else sum+=a[i].x+Q.top(),E.push(Q.top()),Q.pop(),d[++r]=a[i].x;
    30         }
    31     }
    32     ans=sum;
    33     for (int i=l;i<=r;i++) sum-=E.top()+d[i],ans=max(ans,sum),E.pop();
    34     printf("%lld",ans);
    35 }
  • 相关阅读:
    开发进度01
    eclipse 调用cmd运行DataX
    kettle 新建DB连接双击打不开
    用户体验评价
    找水王课堂练习
    人月神话阅读笔记01
    用户模板和用户场景
    大道至简阅读笔记03
    第九周
    第八周总结
  • 原文地址:https://www.cnblogs.com/Comfortable/p/10302729.html
Copyright © 2020-2023  润新知