贪心[偏序+treap]

贪心[偏序+treap]

C. Booking System

题意:一个餐馆,n批顾客,每批顾客都想要坐在同一张桌子上,人数为c,将付的钱是p,m张桌子,有容量desk_c,得到最多的钱,输出两两配对结果;

题解:贪心,有两种贪心策略:

1.让桌子选,根据容量从小到大依次选,选可以满足要人数求中钱最多的
2.让人选,钱从大到小,选可以满足人数要求的桌子容量最小的;[最后一句的要求针对同一对象,可以二分实现]

显然,两种是一样的,而后者好写。

注意点:set默认小根堆,否则multiset<desk,greater>s;

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace IO {
#define gc getchar()
#define pc(x) putchar(x)
    template<typename T>inline void read(T &x) {
        x=0;
        int f=1;
        char ch=gc;
        while(ch>'9'||ch<'0') {
            if(ch=='-')f=-1;
            ch=gc;
        }
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=gc;
        x*=f;
        return;
    }
    template<typename T>inline void write(T x=0) {
        T wr[51];
        wr[0]=0;
        if(x<0)pc('-'),x=-x;
        if(!x)pc(48);
        while(x)wr[++wr[0]]=x%10,x/=10;
        while(wr[0])pc(48+wr[wr[0]--]);
        return;
    }
}
using IO::read;
using IO::write;

const int maxn=1e6+5;
struct kunden{
    int id,c,p;
    bool operator<(const kunden &k2) const {
        return p>k2.p;//按钱从大到小
    }
}k[maxn];
struct desk{
    int id,c;
    bool operator<(const desk &d2) const {
        return c<d2.c;//按照容量从小到大
    }
}d[maxn];
multiset<desk>::iterator it;
int main()
{
    int n,m;multiset<desk>s;ll sum=0;vector<pair<int,int>>vc;
    read(n);for(int i=1;i<=n;i++)k[i].id=i,read(k[i].c),read(k[i].p);
    read(m);for(int i=1;i<=m;i++)d[i].id=i,read(d[i].c),s.insert(d[i]);
    sort(k+1,k+1+n);//按钱从大到小排序
    for(int i=1;i<=n;i++)
    {
        it=s.lower_bound(desk{0,k[i].c});
        if(it!=s.end())
        {
            sum+=k[i].p;
            vc.push_back({k[i].id,(*it).id});
            s.erase(it);
        }
    }
    sort(vc.begin(),vc.end());
    cout<<vc.size()<<' '<<sum<<endl;
    for(auto x:vc)cout<<x.first<<' '<<x.second<<endl;
}
牛客小白月赛29-A.进攻

题意:

scimoon 率领的反叛军已经做好了准备

他的手下有 n 个战机,每架战机有一个破坏力 a

帝国有 m 个基地,每个基地有一个防御值 d,基地有一个价值 v

若一个战机的攻击力严格大于基地的防御值,则可以破坏该基地,得到这个基地的价值 v

帝国的后备资源很多,一个基地可以被反复破坏

每架战机最多只能选择一个基地攻击,当然也可以不攻击[价值可以是负数]

求能获得的最大贡献

题解:两种贪心策略

1.让战机来选,选择可以破防的价值最大的

3.让基地来选,基地按照价值从大到小,每次选择剩下的中可以攻破自己的所有战机,产生的贡献是选择的战机数量*v

注意点:价值可以是负数,这题可以不要用treap,这题的想法用在上一题,也可以不用treap

#include<bits/stdc++.h>
using namespace std;
namespace IO {
#define gc getchar()
#define pc(x) putchar(x)
    template<typename T>inline void read(T &x) {
        x=0;
        int f=1;
        char ch=gc;
        while(ch>'9'||ch<'0') {
            if(ch=='-')f=-1;
            ch=gc;
        }
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=gc;
        x*=f;
        return;
    }
    template<typename T>inline void write(T x=0) {
        T wr[51];
        wr[0]=0;
        if(x<0)pc('-'),x=-x;
        if(!x)pc(48);
        while(x)wr[++wr[0]]=x%10,x/=10;
        while(wr[0])pc(48+wr[wr[0]--]);
        return;
    }
}
using IO::read;
using IO::write;
typedef long long ll;
const int maxn=1e7+100;
#define v first
#define d second
ll a[maxn];pair<ll,ll>b[maxn];
int main()
{
    ll n,m;ll sum=0;
    read(n),read(m);
    for(int i=1;i<=n;i++) read(a[i]);
    for(int i=1;i<=m;i++) read(b[i].d);
    for(int i=1;i<=m;i++) read(b[i].v);
    sort(a+1,a+1+n);
    sort(b+1,b+1+n);
    int last =n+1;
    for(int i=m;i>=1;i--)
    {
        int t=upper_bound(a+1,a+last,b[i].d)-a;
        if(t==last) continue;
        else {
            sum+=b[i].v*(last-t);
            last=t;
        }
        if(t==1) break;
    }
    printf("%lld\n",sum);
}

posted @ 2020-11-14 20:31  zx0710  阅读(96)  评论(0编辑  收藏  举报