Codeforces 436E Cardboard Box (看题解)

Cardboard Box

贪了个半天贪不对, 我发现我根本就不会贪心。

我们先按b排序, 然后枚举选两颗心的b的最大值, 在这个之前的肯定都要选一个, 因为前面的要是一个都没选的话,

你可以把当前选两颗心的替换成前面选两颗心, 然后用平衡树或者线段树维护一下前k大和就好啦。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ull unsigned long long

using namespace std;

const int N = 3e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const double PI = acos(-1);

#define lson l, mid, rt->ls
#define rson mid + 1, r, rt->rs
struct Node {
    Node() {
        ls = rs = NULL;
        sum = cnt = 0;
    }
    Node *ls, *rs;
    LL sum;
    int cnt;
};

inline void pull(Node* rt) {
    rt->cnt = rt->ls->cnt + rt->rs->cnt;
    rt->sum = rt->ls->sum + rt->rs->sum;
    if(!rt->ls->cnt) delete rt->ls, rt->ls = NULL;
    if(!rt->rs->cnt) delete rt->rs, rt->rs = NULL;
}
inline void push(Node* rt) {
    if(!rt->ls) rt->ls = new Node();
    if(!rt->rs) rt->rs = new Node();
}
void update(int p, int c, int l, int r, Node* rt) {
    if(l == r) {
        rt->cnt += c;
        rt->sum += 1LL * p * c;
        return;
    }
    push(rt);
    int mid = l + r >> 1;
    if(p <= mid) update(p, c, lson);
    else update(p, c, rson);
    pull(rt);
}
LL query(int k, int l, int r, Node* rt) {
    if(!k) return 0;
    if(rt->cnt <= k) return rt->sum;
    if(l == r) return 1LL * k * l;
    push(rt);
    int mid = l + r >> 1;
    if(rt->ls->cnt >= k) return query(k, lson);
    else return query(rt->ls->cnt, lson) + query(k - rt->ls->cnt, rson);
}

int n, w, a[N], b[N], id[N], fin[N];
LL ans = INF;

bool cmpa(int x, int y) {
    return a[x] < a[y];
}
bool cmpb(int x, int y) {
    return b[x] < b[y];
}
int main() {
    Node* Rt = new Node();
    scanf("%d%d", &n, &w);
    for(int i = 1; i <= n; i++) scanf("%d%d", &a[i], &b[i]);
    for(int i = 1; i <= n; i++) id[i] = i;
    int where = -1;
    sort(id + 1, id + 1 + n, cmpa);
    if(w <= n) {
        LL ret = 0;
        for(int i = 1; i <= w; i++) ret += a[id[i]];
        ans = min(ans, ret);
        where = 0;
    }
    sort(id + 1, id + 1 + n, cmpb);
    for(int i = 1; i <= n; i++) update(a[id[i]], 1, 1, inf, Rt);
    LL prefix = 0;
    LL ret = 0;
    for(int i = 1; i <= n; i++) {
        int x = id[i];
        update(a[x], -1, 1, inf, Rt);
        ret = prefix + b[x];
        int need = w - (i + 1);
        if(Rt->cnt >= need) {
            ret += query(need, 1, inf, Rt);
            if(ret < ans) {
                ans = ret;
                where = i;
            }
        }
        prefix += a[x];
        update(b[x] - a[x], 1, 1, inf, Rt);
    }
    if(!where) {
        sort(id + 1, id + 1 + n, cmpa);
        for(int i = 1; i <= w; i++) fin[id[i]] = 1;
    } else {
        priority_queue<PII, vector<PII>, greater<PII> > que;
        fin[id[where]] = 2;
        w -= where + 1;
        for(int i = 1; i < where; i++) que.push(mk(b[id[i]] - a[id[i]], i)), fin[id[i]] = 1;
        for(int i = where + 1; i <= n; i++) que.push(mk(a[id[i]], i));
        while(w--) {
            int who = que.top().se;
            que.pop();
            if(who < where) fin[id[who]] = 2;
            else fin[id[who]] = 1;
        }
    }
    printf("%lld\n", ans);
    for(int i = 1; i <= n; i++) printf("%d", fin[i]);
    puts("");
    return 0;
}

/*
*/

原文地址:https://www.cnblogs.com/CJLHY/p/10669817.html

时间: 2024-10-06 07:32:03

Codeforces 436E Cardboard Box (看题解)的相关文章

Codeforces 830C Bamboo Partition (看题解)

Bamboo Partition 列公式, 整除分块, 想不到, 好菜啊. #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x)

Codeforces 875F Royal Questions (看题解)

我还以为是什么板子题呢... 我们把儿子当做点, 公主当做边, 然后就是求边权值最大基环树森林. #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #de

Codeforces 263E Rhombus (看题解)

Rhombus 不想写标程啊, 转成切比雪夫距离暴力就能过啦.. 复杂度n * m * k, 其实复杂度能处理到n * m #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #

Codeforces 750E New Year and Old Subsequence 线段树 + dp (看题解)

New Year and Old Subsequence 第一感觉是离线之后分治求dp, 但是感觉如果要把左边的dp值和右边的dp值合起来, 感觉很麻烦而且时间复杂度不怎么对.. 然后就gun取看题解了, 用线段树维护dp的值, 然后区间合并求答案. 每个节点保存dp[ i ][ j ]表示, 把当前管理的区间删到 s{2017}中的 s[ i + 1 ] - s[ j - 1 ],最少删几个, 然后合并的时候5 ^ 3合并. #include<bits/stdc++.h> #define L

Codeforces Round #177 (Div. 2) 题解

[前言]咦?现在怎么流行打CF了?于是当一帮大爷在执着的打div 1的时候,我偷偷的在刷div 2.至于怎么决定场次嘛,一般我报一个数字A,随便再拉一个人选一个数字B.然后开始做第A^B场.如果觉得机密性不高,来点取模吧.然后今天做的这场少有的AK了.(其实模拟赛只做完了4题,最后1题来不及打了) 等等,话说前面几题不用写题解了?算了,让我难得风光一下啦. [A] A. Polo the Penguin and Segments time limit per test 2 seconds mem

Codeforces Round #561 (Div. 2) 题解

Codeforces Round #561 (Div. 2) 题解 题目链接 A. Silent Classroom 水题. Code #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 105; int n; char s[N], t[N]; int main() { cin >> n; for(int i = 1; i <= n; i++) { scanf(&q

Codeforces Round #608 (Div. 2) 题解

目录 Codeforces Round #608 (Div. 2) 题解 前言 A. Suits 题意 做法 程序 B. Blocks 题意 做法 程序 C. Shawarma Tent 题意 做法 程序 D. Portals 题意 做法 程序 E. Common Number 题意 做法 程序 结束语 Codeforces Round #608 (Div. 2) 题解 前言 题目链接:仅仅只是为了方便以题目作为关键字能查找到我的题解而已(逃 Codeforces 1271A Codeforce

Codeforces Round #617 (Div. 3) 题解

目录 Codeforces Round #617 (Div. 3) 题解 前言 A. Array with Odd Sum 题意 做法 程序 B. Food Buying 题意 做法 程序 C. Yet Another Walking Robot 题意 做法 程序 D. Fight with Monsters 题意 做法 程序 E1. String Coloring (easy version) 题意 做法 程序 E2. String Coloring (hard version) 题意 做法

Codeforces A. Valera and X 题解

判断二维字符串是否满足下面条件: on both diagonals of the square paper all letters are the same; all other squares of the paper (they are not on the diagonals) contain the same letter that is different from the letters on the diagonals. Help Valera, write the progra