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 ↩︎

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