【HDU6742 2019 CCPC 秦皇岛 】MUV LUV ALTERNATIVE 曼哈顿剧院 两出口观众逃生最短时间

 

应岛娘邀请,自费机票回国打比赛。

队名——友谊是魔法。最终榜单如下——https://ccpc.io/post/187

 

这题是场上的L题。

一年多不写题也不想题情况下遇上了这场比赛的L题。是个贪心题,所以恰好撞我枪口上了。

不夸张地哦,读完题后三分钟内我就会做啦!

但是我们读到这道题太晚了,加上当时队友 岛娘 也 大概会做了(噗哈哈>__<),然后题意读得略有误,导致了罚时,最后拿到二血。

 

 

但是全场最终只有四个队通过该题,还有2个是杜老师和吉老师的血强神仙队伍。

怎么搞的,你们这群现役小弟弟。哈哈哈,我的贪心水平还是国内挺强的吧,毕竟前队友 cls 都忍不住夸我呢~

 

哈,代码如下 —— 

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template inline void gmin(T1 &a, T2 b) { if (b >s1, s2;
        multiseto1, o2;
        int omni = 0;
        for(int i = 1; i <= K; ++i) {
            int pos, x, y;
            scanf("%d%d%d", &pos, &x, &y);
            LL d1 = abs(L1 + 1 - y) + x;
            LL d2 = abs(L1 + L2 + 2 - y) + x;
            if(pos == 1)d2 = 1e12;
            else if(pos == 3)d1 = 1e12;
            s1.insert({d1, d2});
            s2.insert({d2, d1});
        }
        LL now = 1;
        while(true) {
            while(!s1.empty()) {
                LL x = s1.begin()->first;
                LL y = s1.begin()->second;
                if(x <= now) {
                    o1.insert(y);
                    s1.erase(s1.begin());
                    s2.erase(s2.find({y, x}));
                }
                else break;
            }
            while(!s2.empty()) {
                LL x = s2.begin()->first;
                LL y = s2.begin()->second;
                if(x <= now) {
                    o2.insert(x);
                    s2.erase(s2.begin());
                    s1.erase(s1.find({y, x}));
                }
                else break;
            }
            while(!o1.empty()) {
                if(*o1.begin() <= now) {
                    o1.erase(o1.begin());
                    ++omni;
                }
                else break;
            }
            while(!o2.empty()) {
                if(*o2.begin() <= now) {
                    o2.erase(o2.begin());
                    ++omni;
                }
                else break;
            }
            bool flag = 0;
            if(!o1.empty()) {
                o1.erase(--o1.end());
                flag = 1;
            }
            else if(omni){
                --omni;
                flag = 1;
            }
            if(!o2.empty()) {
                o2.erase(--o2.end());
                flag = 1;
            }
            else if(omni){
                --omni;
                flag = 1;
            }
            if(flag)++now;
            else if(s1.empty())break;
            else now = min(s1.begin()->first, s2.begin()->first);
        }
        printf("%lld\n", now - 1);
    }
    return 0;
}

现场过的队伍,包括出题人的标程,都应该是基于二分答案下的O(nlognlogn),当然按照吉老师原话是——"应该可以O(nlogn),但是没必要"。但是,按照我的做法,是直接就是O(nlogn)。

 

做出这道题的核心关键,就是要意识到——影响流量(就是逃出该场地)的最关键的限制口,其实是两个出口处。我们只需要基于所有人到达该出口处的时间,做适当的排序并贪心就好了。
 

我这边好像人有三类——

1,只能从出口一逃离的人(记在o1的set里,按照到达时间小的优先出出口)

2,只能从出口二逃离的人(记在o2的set里,按照到达时间小的优先出出口)

3,两个出口都可以逃出的全能人,直接用integer omni计数即可。当出口一二没有o1或o2的人逃出时,才使用omni逃(因为他们随时都可以从任何一个出口逃,所以显然作为殿后者最合适)。

然后滚动时间轴,贪心着模拟一下即可AC

具体细节还未证明,以后有时间可以慢慢补上。

你可能感兴趣的:(贪心,脑洞,好题)