【HDU6742 2019 CCPC 秦皇島 】MUV LUV ALTERNATIVE 曼哈頓劇院 兩出口觀衆逃生最短時間

 

應島娘邀請,自費機票回國打比賽。

隊名——友誼是魔法。最終榜單如下——https://ccpc.io/post/187

 

這題是場上的L題。

一年多不寫題也不想題情況下遇上了這場比賽的L題。是個貪心題,所以恰好撞我槍口上了。

不誇張地哦,讀完題後三分鐘內我就會做啦!

但是我們讀到這道題太晚了,加上當時隊友 島娘 也 大概會做了(噗哈哈>__<),然後題意讀得略有誤,導致了罰時,最後拿到二血。

 

 

但是全場最終只有四個隊通過該題,還有2個是杜老師和吉老師的血強神仙隊伍。

怎麼搞的,你們這羣現役小弟弟。哈哈哈,我的貪心水平還是國內挺強的吧,畢竟前隊友 cls 都忍不住誇我呢~

 

哈,代碼如下 —— 

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
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 <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 2e5 + 10, M = 0, Z = 1e9 + 7, INF = 0x3f3f3f3f;
int casenum, casei;
int n, K;
LL L1, L2, L3;
int main()
{
    while(~scanf("%d%lld%lld%lld%d", &n, &L1, &L2, &L3, &K)) {
        multiset< pair<LL,LL> >s1, s2;
        multiset<LL>o1, 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

具體細節還未證明,以後有時間可以慢慢補上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章