Codeforces GoodBye2015 New Year and Three Musketeers Codeforces 611E(贪心)

这道题在比赛的时候一直在想二分答案+贪心判定,结果一直在WA on pretest10……第二天起来一想,发现是有问题的……因为在判定的时候,我是把每一次操作隔离开来看的,但他要求是同时干某件事,所以不能直接给每个人分配k次出手机会。
比如说,现在的分配情况是:
a——b——c
&——_——&
_——&——&
a、c和b、c各一次,如果用之前的策略的话,就还可以用一次a、b,但是,a、b的可用时间是不一样的,所以这是行不通的。

我们现在考虑,一个时间,一个时间地模拟,那么,我们可以模糊地想象出一个贪心的策略。

贪心部分代码:

我们假设a<b<c
注:work(t)是指干掉≤t的最大的一个。
if(mx <= a)    //当最大的<a那么所有的怪都可以被任何一个musketeers消灭
{
    cnt --;
    cnt += (n+2)/3;
    break;
}
else if(mx <= b)//当a < mx <= b时,a先干掉a能干的,b、c干掉最大的两个。
{
    sbt.work(a);
    sbt.work(b);
    sbt.work(c);
}
else if(mx <= c)//当b < mx <= c 时,若a和b都可以干掉一个,那么就分别干掉一个,如果a和b只能干掉一个或更少,那么就用a+b去干掉能干掉的最大的,显然更优。c干掉最大的。
{
    bool flag = true;
    int tmp = sbt.Prev(sbt.root, a);
    if(tmp != -1)
    {
        int s1 = tmp;
        sbt.erase(sbt.root, tmp);
        tmp = sbt.Prev(sbt.root, b);
        if(tmp != -1)
        {
            sbt.erase(sbt.root, tmp);
            n -= 2;
            sbt.work(c);
        }
        else
        {
            sbt.insert(sbt.root, s1);
            flag = 0;
        }
    }
    else flag = 0;
    if(!flag)
    {
        int aa = a+b, bb = c;
        if(aa > bb) swap(aa, bb);
        sbt.work(aa);
        sbt.work(bb);
    }
}
// 考虑多个人一起打怪
else if(mx <= a + b) // c < mx <= a+b
{
    int aa = c, bb = a + b;
    sbt.work(aa);
    sbt.work(bb);
}
else if(mx <= a + c) // c, a+b < mx <= a + c
{
    int aa = b, bb = a + c;
    sbt.work(aa);
    sbt.work(bb);
}
else if(mx <= c + b) // c, a+b, < a+c < mx <= b + c
{
    int aa = a, bb = c + b;
    sbt.work(aa);
    sbt.work(bb);
}
else
{
    sbt.work(a+b+c);
}

代码

#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 200005
#define INF 0x3f3f3f3f
int n, m, a, b, c, C[3], sd = 2333, sz;
int t[MAXN];
char ch, f;
inline void GET(int &n) {
    n = 0; f = 1;
    do {ch = getchar(); if(ch == '-') f = -1;} while(ch > '9' || ch < '0');
    while(ch >= '0' && ch <= '9') {n=n*10+ch-'0';ch=getchar();}
    n *= f;
}
struct Treap {
    struct Node {
        int v, s[2], cnt, rnd;
    } t[MAXN];
    int root;
    const inline int Rand() { return sd = sd * sd % 1000007; }
    inline void Rot(int &k, bool f) {
        int p = t[k].s[f]; t[k].s[f] = t[p].s[f^1];
        t[p].s[f^1] = k; k = p;
    }
    void insert(int &k, int v) {
        if(!k) { k = ++ sz; t[k].v = v; t[k].rnd = Rand(); t[k].cnt = 1; return; }
        if(t[k].v == v) { ++ t[k].cnt; return; }
        bool f = v > t[k].v;
        insert(t[k].s[f], v);
        if(t[t[k].s[f]].rnd > t[k].rnd) Rot(k, f);
    }
    void erase(int &k, int v) {
        if(!k) return;
        if(t[k].v == v) {
            if(t[k].cnt > 1) -- t[k].cnt;
            else if(t[k].s[0] * t[k].s[1] == 0) k = t[k].s[0] + t[k].s[1];
            else {
                bool f = t[t[k].s[1]].rnd > t[t[k].s[0]].rnd;
                Rot(k, f); erase(k, v);
            }
            return;
        }
        bool f = v > t[k].v;
        erase(t[k].s[f], v);
    }
    const int Prev(int k, int v, int p = 200003) {
        if(!k) return t[p].v;
        else if(t[k].v == v) return v;
        else if(t[k].v < v) return Prev(t[k].s[1], v, k);
        else return Prev(t[k].s[0], v, p);
    }
    const bool size() { return root; }
    const int Max() {
        int tmp = root;
        while(t[tmp].s[1]) tmp = t[tmp].s[1];
        return t[tmp].v;
    }
    void work(int val) {
        if(!root) return;
        int tmp = Prev(root, val);
        if(tmp == -1) return;
        n --;
        erase(root, tmp);
    }
} sbt;
int main() {
    scanf("%d", &n); sbt.root = 0; sbt.t[200003].v = -1;
    scanf("%d%d%d", &a, &b, &c);
    if(a > b) swap(a, b);
    if(a > c) swap(a, c);
    if(b > c) swap(b, c);
    for(int i = 1; i <= n; ++ i) {
        GET(t[i]);
        sbt.insert(sbt.root, t[i]);
    }
    if(sbt.Max() > a + b + c) { puts("-1"); return 0; }
    int cnt = 0;
    for(;sbt.size() && n;) {
        ++ cnt;
        C[0] = C[1] = C[2] = 0;
        int mx = sbt.Max();
        if(mx <= a) {
            cnt --;
            cnt += (n+2)/3;
            break;
        }
        else if(mx <= b) {
            sbt.work(a);
            sbt.work(b);
            sbt.work(c);
        }
        else if(mx <= c) {
            bool flag = true;
            int tmp = sbt.Prev(sbt.root, a);
            if(tmp != -1) {
                int s1 = tmp;
                sbt.erase(sbt.root, tmp);
                tmp = sbt.Prev(sbt.root, b);
                if(tmp != -1) {
                    sbt.erase(sbt.root, tmp);
                    n -= 2;
                    sbt.work(c);
                } else {
                    sbt.insert(sbt.root, s1);
                    flag = 0;
                }
            } else flag = 0;
            if(!flag) {
                int aa = a+b, bb = c;
                if(aa > bb) swap(aa, bb);
                sbt.work(aa);
                sbt.work(bb);
            }
        }
        else if(mx <= a + b) {
            int aa = c, bb = a + b;
            sbt.work(aa);
            sbt.work(bb);
        }
        else if(mx <= a + c) {
            int aa = b, bb = a + c;
            sbt.work(aa);
            sbt.work(bb);
        }
        else if(mx <= c + b) {
            int aa = a, bb = c + b;
            sbt.work(aa);
            sbt.work(bb);
        }
        else {
            sbt.work(a+b+c);
        }
    }
    printf("%d\n", cnt);
    return 0;
}

转载于:https://www.cnblogs.com/geng4512/p/5296879.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值