题目描述

 

小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战队的指挥,请制定一套最优的降落方案,使得最后获得的团队奖励总积分最大

 

 

输入

 

第一行包含两个正整数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),分别表示每个敌人的子弹数和奖励积分。

 

输出

 

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

 

 

样例输入

<span style="color:#333333"><span style="color:#333333">3 3
4 4 4
2 3
1 3
5 3</span></span>

样例输出

<span style="color:#333333"><span style="color:#333333">11</span></span>

来源

Lydsy1708月赛

题解:

一个敌人的贡献显然就是c-b,前提是a>b。

所以我们将两个数组排序一下,枚举一个a,将所有小于a的b全部加入堆,取最大即可

注意:算完一个a的答案之后,还要将-a加入堆中。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,a[100005],Min=1e9,u[100005],F,R;
struct Node
{
    int b,c;
    bool operator < (const Node &T) const {return c<T.c;}
}s[100005];
bool cmp(Node t1,Node t2){return t1.b<t2.b;}
long long ans;
priority_queue<Node>Q;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    for(int i=1;i<=m;++i)
        scanf("%d%d",&s[i].b,&s[i].c),Min=min(Min,s[i].b),s[i].c-=s[i].b;
    sort(a+1,a+1+n);
    sort(s+1,s+1+m,cmp);
    int t=1;
    for(int i=1;i<=n;++i)
    {
        while(s[t].b<a[i]&&t<=m)Q.push(s[t]),t++;
        if(!Q.empty())
        {
            int sum=-1e9;
            if(F<R)sum=-u[F+1];
            if(sum<=Q.top().c)ans+=(long long)Q.top().c+a[i],Q.pop();
            else F++,ans+=a[i]+sum;
            u[++R]=a[i];
        }
        else
        {
            if(F<R)ans=ans-u[++F]+a[i],u[++R]=a[i];
        }
    }
    cout<<ans;
}