bzoj4977 跳伞求生——贪心

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4977

今天讲的贪心题,真神奇啊;

首先,要得到尽量多选队友的解;

把队友按 a[i] 从小到大排序,敌人按 b[i] 从小到大排序,然后对于每个队友,选择能攻击的、收益最多的敌人;

如果没有能攻击的敌人,就把之前最小的一个队友踢掉代替,能使答案更优;

但尽量多选队友不一定是最终的最优答案,因为有些价值很小(为负)的敌人不如不选;

所以需要调整,很妙的做法,就是直接踢掉最小的队友和收益最小的敌人,那么剩下的队友和敌人也一定可以配对,过程中取最优解;

于是去写了,然而秒WA,自己码力好弱啊,打击...

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
int const maxn=1e5+5,inf=1e9;
int n,m,a[maxn];
ll ans;
bool vis[maxn],out[maxn];
struct N{
    int b,c,bh;
    bool operator < (const N &y) const
    {
        return c-b<y.c-y.b;//priority_queue大根堆 
    }
}p[maxn],t[maxn];
priority_queue<N>qen;
priority_queue<int>q2;
priority_queue<int>q;
bool cmp(N x,N y){return x.b<y.b;}
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",&p[i].b,&p[i].c);
    sort(a+1,a+n+1); sort(p+1,p+m+1,cmp);
    for(int i=1;i<=m;i++)p[i].bh=i;
    int j=1,pr=1;
    for(int i=1;i<=n;i++)
    {
        while(p[j].b<=a[i]) {qen.push(p[j]); j++;}
        if(!qen.size()) {t[i]=t[pr]; out[pr]=1; pr++;}
        else {t[i]=qen.top(); vis[t[i].bh]=1; qen.pop();}
    }
    for(int i=1;i<=n;i++)
        if(!out[i])ans+=a[i]-t[i].b+t[i].c;
    for(int i=1;i<=m;i++) if(vis[i])q2.push(p[i].b-p[i].c);
    for(int i=1;i<=n;i++) if(!out[i])q.push(-a[i]);//
    ll tmp=ans;
    while(q.size()&&q2.size())
    {
        int x=-q.top(); q.pop();
        int y=-q2.top(); q2.pop();
        tmp-=x; tmp-=y;
        ans=max(ans,tmp);
    }
    printf("%lld\n",ans);
    return 0;
}

看看人家写的简洁优美AC代码:https://blog.csdn.net/dream_lolita/article/details/79302382

然后就模仿着写了;练习码力...

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
int const maxn=1e5+5;
int n,m,w[maxn],hd,tl;
ll ans,sum;
struct N{
    int x,y; bool tp;
    bool operator < (const N &b) const
    {
        if(x==b.x)return tp<b.tp;
        else return x<b.x;
    }
    N(int x=0,int y=0,bool t=0):x(x),y(y),tp(t) {}
}t[maxn<<1];
priority_queue<int>q;
priority_queue<int,vector<int>,greater<int> >p;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,x;i<=n;i++)scanf("%d",&t[i].x);
    for(int i=1,x,y;i<=m;i++)
    {
        n++;
        scanf("%d%d",&x,&y);
        t[n]=N(x,y-x,1);
    }
    sort(t+1,t+n+1);
    hd=1;
    for(int i=1;i<=n;i++)
    {
        if(t[i].tp)q.push(t[i].y);
        else
        {
            if(!q.size())
            {
                if(hd<=tl)
                {
                    int tmp=w[hd]; hd++;
                    sum+=t[i].x-tmp;
                    w[++tl]=t[i].x;
                }
            }
            else
            {
                int tmp=q.top(); q.pop();
                sum+=t[i].x+tmp;
                p.push(tmp);//tmp被使用过 
                w[++tl]=t[i].x;
            }
        }
    }
    ans=sum;
    for(int i=hd;i<=tl;i++)
    {
        sum-=w[i]+p.top(); p.pop();
        ans=max(ans,sum);
    }
    printf("%lld\n",ans);
    return 0;
}

 

转载于:https://www.cnblogs.com/Zinn/p/9319745.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值