zoukankan      html  css  js  c++  java
  • AGC018C Coins (set)

    题目大意:

    给出n个人,每个人手里都有xi个金牌,yi个银牌,ci个铜牌。

    你需要选出X个人,拿走他们手里的金牌,选出Y个人,拿走他们手里的银牌,选出Z个人,拿走他们手里的铜牌

    X+Y+Z = n。并且选的这X,Y,Z个人里不能有重复的。

    题解:

    不妨先考虑只有金牌和银牌怎么做。

    如果只有两种,就变成很简单的贪心了,依据每个人手中的金牌数x减去银牌数y然后排序,按差值选即可

    现在又多了一个铜牌,我们还是按照这个思路

    依据每个人手中的金牌数x减去银牌数y然后排序。

    然后我们考虑如何分配我们的X和Y。

    注意到,排完序以后,这里有一个奇妙的性质出现了

    这个性质简单来说就是,银牌从排序靠前的元素选,金牌从排序靠后的元素选,这样做会更优

    或者这样说,银牌和金牌的选择是互不交叉的。(考虑如果有交叉,那么相互交换一下会更优)

    那么我们就可以这样求出答案

    枚举一个k,从前k个元素中选出Y个银牌,从后n-k个元素中选出X个金牌,其他都是选铜牌

    这样我们只需要把k从Y枚举到n-X就可以了

    那铜牌的影响怎么处理呢?

    就让金牌数和银牌数直接减去铜牌数,然后最后的答案加上铜牌数,这样所有的铜牌数就变成了0

    就可以不考虑它的影响了。

    对每一个k,答案就是前k个元素中最大的Y个银牌数和,加上后n-k个元素中最大的X个银牌数和

    这个显然可以用set来维护。

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <set>
    #include <map>
    #define fi first
    #define se second
    using namespace std;
    const int maxn = 1e5 + 100;
    typedef pair<int, int> PII;
    bool cmp(const PII &A, const PII &B){
        return A.fi - A.se < B.fi - B.se;
    }
    PII a[maxn];
    set<int> S[3];
    map<int, int> H[3];
    int ssz[3], sz[3];
    long long ans = 0, temp, ans1[maxn], ans2[maxn];
    void Erase(int x, int ty){
        if(H[ty][x] == 1) S[ty].erase(x);
        H[ty][x]--;
        ans -= x;
        ssz[ty]--;
    }
    void Insert(int x, int ty){
        if(H[ty][x] == 0) S[ty].insert(x);
        H[ty][x]++;
        ans += x;
        ssz[ty]++;
    }
    
    void S_Insert(int x, int ty){
        if(ssz[ty] == sz[ty]){
            int y = *S[ty].begin();
            if(y > x) return;
            Erase(y, ty);
        }
        Insert(x, ty);
    }
    
    int main()
    {
        int X, Y, Z, x, y, z;
        cin>>X>>Y>>Z;
        int n = X+Y+Z;
        for(int i = 1; i <= n; i++){
            scanf("%d %d %d", &x, &y, &z);
            x -= z;
            y -= z;
            ans += z;
            a[i].fi = x;
            a[i].se = y;
        }
        temp = ans;
        ans = 0;
        sort(a+1, a+1+n, cmp);
        sz[1] = Y; sz[0] = X;
        for(int i = 1; i <= Y; i++) S_Insert(a[i].se, 1);
        ans1[Y] = ans;
        for(int i = Y+1; i <= n-X; i++){
            S_Insert(a[i].se, 1);
            ans1[i] = ans;
        }
        ans = 0;
        for(int i = n; i >= n-X+1; i--) S_Insert(a[i].fi, 0);
        ans2[n-X+1] = ans;
        for(int i = n-X; i >= Y+1; i--){
            S_Insert(a[i].fi, 0);
            ans2[i] = ans;
        }
        ans = -1e18;
        for(int i = Y; i <= n-X; i++) ans = max(ans, ans1[i]+ans2[i+1]);
        cout<<ans+temp<<endl;
        return 0;
    }
  • 相关阅读:
    Springboot html映射
    table 合并单元格
    Idea中Spring Boot 启动出错
    Modal模态框scrolltop保留上次位移的解决方案
    8、如何实现浏览器的前进、后退操作?
    html中table并排展示
    两个有序的链表的合并
    7、链表(下):如何轻松写出正确的链表代码?
    2018.10.12
    c语言关键字:const
  • 原文地址:https://www.cnblogs.com/Saurus/p/7239252.html
Copyright © 2011-2022 走看看