CodeForces Hello2020 D. New Year and Conference 題解(中文版)

這篇博客講 Codeforces Hello2020 的 D 題。

題目鏈接:

Hello2020 D. New Year and Conference

describe:

(懶得翻譯了,打開網站或看照片把 QAQ
可以看照片(

solution

1
先只考慮 a venue。如何快速判斷出所有的 overlop?可以構建一個集合,以時間點(saea 混在一起)爲關鍵字排序,由前到後的順序,有以下兩個操作:

  • 若該時刻有 lecture 開始,則將其加入集合。(該過程結束後,集合中所有 lectures 都 overlop。)
  • 若該時刻有 lecture 結束,則讓其離開集合。

如果我們在加入 a venue 的同時也把 對應 lecture 的 sb eb 也加進去了(由於集合是以 sa ea 排序的,所以 sb eb 很可能是亂序的),那麼我們就可以由該時刻集合中所有 lectures 的 sbmaxebmin 的關係判斷 b venue 的 lectures 是否全部 overlop( 即 sbmax<=ebmin 時 overlop)。
sbmaxebmin 的獲得可由 <set> 中的 multiset 實現,單次操作複雜度爲 O(logn)

易知“任意時刻該集合中 b venue 都 overlop”是 venue-sensitive 的必要條件,我們記這樣的結果爲“成功”。一次該過程複雜度爲 O(nlogn)
若成功,我們就可以得到這樣一個單向的結論:對於每對在 a venue 中 overlop 的 lectures,它們在 b venue 中也 overlop。
然後我們只需交換 ab venue 的時間,再進行相同的過程,即可得到反向結論。
易知“兩次過程都成功”是 venue-sensitive 的充要條件。總體複雜度爲 O(nlogn)

code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;
const int N=1e5+10;

struct Node
{
	int as, ae, bs, be;
	bool operator < (const Node &a) const { return ae>a.ae; }
}stu1[N], stu2[N];

bool cmp(Node a, Node b) { return a.as<b.as; }

int n;
int tim[N<<1];
priority_queue <Node> Q;
multiset<int> Ss, Se;

bool check(Node *stu)
{
	int tn=0; Node sc;
	sort(stu, stu+n, cmp);
	for(int i=0; i<n; ++i) tim[i<<1]=stu[i].as, tim[i<<1|1]=stu[i].ae;
	sort(tim, tim+n*2);
	for(int i=1; i<n*2; ++i) if(tim[i]!=tim[tn]) tim[++tn]=tim[i];
	tn++;
// 好像以上的步驟可以用一些神奇的函數輕易做到,但菜雞我不會啊qwq
	while(!Q.empty()) Q.pop();
	Ss.clear(); Se.clear();
	for(int i=0, cur=0, t; i<tn; ++i)
	{
		t=tim[i];
		do
		{
			sc=stu[cur];
			if(sc.as==t)
			{
				Q.push(sc);
				cur++;
				Ss.insert((-1)*sc.bs);//菜雞我不知道怎麼由大到小排序qwq
				Se.insert(sc.be);
				if(Q.size()>1&&(*Ss.begin())*(-1)>*Se.begin()) return false;
			}
		}while(sc.as==t && cur<n);
		do
		{
			sc=Q.top();
			if(sc.ae==t)
			{
				Q.pop();
				Ss.erase((-1)*sc.bs);
				Se.erase(sc.be);
			}
		}while(sc.ae==t&&!Q.empty());
	}
	return true;
}

int main()
{
	//freopen("data.txt","r",stdin);
	//freopen("my.txt","w",stdout);
	scanf("%d", &n);
	for(int i=0; i<n; ++i)
	{
		Node t;
		scanf("%d%d%d%d", &t.as, &t.ae, &t.bs, &t.be);
		stu1[i]=t; stu2[i]=(Node){t.bs,t.be,t.as,t.ae};
	}
	if(check(stu1)&&check(stu2)) puts("YES");
	else puts("NO");
	//fclose(stdout);
	return 0;
}

another sulution:

2
從評論中翻出來了個用隨機數的???竟然還被 hack 失敗???我不明白爲什麼可以啊,誰能告訴我!!!

his code:

#include<bits/stdc++.h>
using namespace std;

struct seg{ int a, b, c, d; };

bool sort1(const seg& a, const seg& b){ return a.a < b.a; }

bool sort2(const seg& a, const seg& b){ return a.c < b.c; }

bool check(vector<seg>& c){
	int n = c.size();
	sort(c.begin(), c.end(), sort1);
	long long check1 = 0;
	
	for(int i = 0; i < n; i++){
		//binary search to find right endpoint
		
		int low = i, high = n-1, mid;
		while(low < high){
			mid = (low + high + 1)/2;
			
			if(c[i].b >= c[mid].a){ //intersect
				low = mid;
			}else{
				high = mid-1;
			}
		}
		mid = (low + high + 1)/2;
		//mid is the one which intersects
		
		check1 += mid - i;
	}
	
	sort(c.begin(), c.end(), sort2);
	long long check2 = 0;
	
	for(int i = 0; i < n; i++){
		//binary search to find right endpoint
		
		int low = i, high = n-1, mid;
		while(low < high){
			mid = (low + high + 1)/2;
			
			if(c[i].d >= c[mid].c){ //intersect
				low = mid;
			}else{
				high = mid-1;
			}
		}
		mid = (low + high + 1)/2;
		//mid is the one which intersects
		
		check2 += mid - i;
	}
	return check2 == check1;
}

signed main(){
	ios::sync_with_stdio(false); 
	cin.tie(0);
	srand(time(NULL));
	int n; cin>>n;
	vector<seg> a(n);
	mt19937 rng;
	for(int i = 0; i < n; i++){
		cin>>a[i].a>>a[i].b>>a[i].c>>a[i].d;
	}
	
	for(int i = 0; i < 60; i++){
		vector<seg> c;
		c.reserve(n);
		for(int j = 0; j < n; j++){
			if(rng()%2 == 0){
				c.push_back(a[j]);
			}
		}
		bool ans = check(c);
		if(!ans){
			cout<<"NO"<<endl;
			return 0;
		}
	}
	cout<<"YES"<<endl;
	
}

reflect

①第一次用 multiset !
②如何識別兩個數列的 py 關係(霧
③竟然可以把 s e 混合起來排序,果然混亂才能包容(?

最後的廢話:

這次 cf 這題理解錯了(其實理解對了也做不出來
菜雞我只能做出3道(我已經很開心了

大一的我還什麼都沒有學,但已經在爲了ACM的夢而努力。

如果真的有人看到了這篇博客(我的榮幸啊!),如果還能解決我的疑惑(比如 multiset 怎麼升序排列,如何離散化,爲什麼可以隨機的程序隨機過),或是發現了什麼問題,或是想到了其他東西,如果還想告訴我的話(真不容易啊),一定要告訴我啊(萬分感謝),如果我能進校隊的話,一定會很感激你的qwq。

怎麼給目錄設置鏈接啊啊啊aaa (感謝評論,我已經會了)


  1. 思路來自 cf官方題解 ↩︎

  2. 看一看他所謂的 randomised sol for D ↩︎

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