[bzoj4977][Lydsy1708月赛]跳伞求生——贪心 大佬们的博客 Some Links

版权声明:欢迎大家转载,转载请标明出处。 https://blog.csdn.net/ylsoi/article/details/81877230

题目大意:

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

思路:

很好的一道题目。
不难发现最后的答案中的 a i 一定是一段最大的后缀,所以我们考虑对于 a i 从小到大排序之后倒着去给每一个 a i 确定答案。
考虑如何确定答案,发现如果选择权值 ( c j b j ) 最大的话会有把后面的人的给选了导致答案不更加优秀的问题,所以我们考虑直接选择最接近目前 a i b i ,这样可以保证选的人数时最多的。但是这样仍然有问题,就是可能有一些 b j 小的没有人选到但是其实如果有些 a i 选这个 b j 的话会更优秀。所以对于每一个没有人选的 b j 我们都去比较一下看是否会更优。
但是这样仍然有问题,现在求的是选的人数最大的时候的最优值,其实有些人的贡献为负数,要把这些人去掉的话直接开两个堆,一个维护 a i ,一个维护 c j b j ,然后每次从里面取出最小的判断要不要删除即可。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a;i<=b;++i)
#define DREP(i,a,b) for(int i=a;i>=b;--i)
#define fi first
#define se second
#define pii pair<int,int>
#define mk make_pair
typedef long long ll;

using namespace std;

void File(){
    freopen("winner.in","r",stdin);
    freopen("winner.out","w",stdout);
}

template<typename T>void read(T &_){
    T __=0,mul=1; char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')mul=-1;
        ch=getchar();
    }
    while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    _=__*mul;
}

const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
int n,m,a[maxn];
pii val[maxn];
ll ans;
multiset<int>st,st1;
multiset<int>::iterator it;

void init(){
    read(n); read(m);
    REP(i,1,n)read(a[i]);
    REP(i,1,m)read(val[i].fi),read(val[i].se);
}

void work(){
    sort(a+1,a+n+1);
    sort(val+1,val+m+1);
    int p=m;
    DREP(i,n,1){
        while(p && val[p].fi>=a[i]){
            it=st.begin();
            if(val[p].se-val[p].fi>*it){
                ans-=*it;
                ans+=val[p].se-val[p].fi;
                st.erase(it);
                st.insert(val[p].se-val[p].fi);
            }
            --p;
        }
        if(!p)break;
        ans+=a[i]+val[p].se-val[p].fi;
        st.insert(val[p].se-val[p].fi);
        st1.insert(a[i]);
        --p;
    }
    while(st.size()){
        int ai=*st1.begin();
        int wi=*st.begin();
        if(ai+wi<0){
            ans-=ai+wi;
            st1.erase(st1.begin());
            st.erase(st.begin());
        }
        else break;
    }
    printf("%lld\n",ans);
}

int main(){
    File();
    init();
    work();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/81877230