Codeforces Round #662 Div.2 (CF1392)

有人说这场背景描述挺烂,不过我觉得还不错(

A题意有点烦,建议直接去看英文原文((

手动画图然后推个结论,挺简单的,不赘述了:

/*
	ID: Loxilante
	Time: 2020/08/07
	Prog: CF1393A
	Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/stdc++.h>
#define rep(i, l, r) for(register int i = l; i < r; i++)
#define hrp(i, l, r) for(register int i = l; i <= r; i++)
#define rev(i, r, l) for(register int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn> inline tn next(void) { tn k; cin>>k; return k; }
signed main(void)
{
	clock_t Begin = clock();

	#ifdef JOEON
//		freopen("C:\Users\Joeon\Desktop\IN.txt", "r", stdin);
//		freopen("C:\Users\Joeon\Desktop\OUT.txt", "w", stdout);
	#endif
	
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int T = next<int>();
	while(T--) cout<<(next<int>())/2+1<<endl;
	
	clock_t InputFinished = clock();
	
	
	
	clock_t End = clock();
	
	D((double)(End-Begin)/CLOCKS_PER_SEC);
	D((double)(End-InputFinished)/CLOCKS_PER_SEC);
	
	return 0;
}
/*

 */

B的意思是给你n和n根木棍,q和q个操作,对于每个操作+ x代表加入一根x长木棍,- x代表删去一根x长木棍,每次操作后输出能不能从中挑出8根木棍分别围成一个正方形和一个矩形(矩形能为正方形)。
(1 <= n,q <= 1e5)
仔细观察下题,其实就是让我们实现一个玩意儿,其中插入,删除,询问时间复杂度要小于(O(n+q))


打cf的时候开始没什么头绪,我的思路也比较绕,不过如果模块化就可以很容易写出来:
首先考虑用cnt数组计数然后用vector存4根木棍相同和2根木棍相同的,这样插入是(O(1)),询问是(O(1)),可是删除是(O(n)),再加上这些操作最多要做q次,总复杂度是(O(qn)),直接T飞。
然后考虑使vector中木棍长度有序然后二分删除,可以先(O(nlogn))排序,类似插入排序思想插入,可是这样插入复杂度是(O(n)),总复杂度(O(n^2)),继续T飞。
等等,刚刚那个思路的前提是木棍长度有序,我不由自主地想到了set。
emmm,set用不了,因为木棍长度可能相同,set不允许元素重复,这时候我们英勇的multiset就出场啦。
multiset,C++98能用,是一个允许元素重复的set,也就是一个内部元素一直有序的容器。
这样的话,用multiset可以实现(O(logn))插入,multiset删除是(O(logn)),我们再二分(O(logn)),所以删除总复杂度是(O((logn)^2)),询问(O(1))


然后考虑实现,可以维护两个multiset,一个four一个two,一个储存4根木棍相同和2根木棍相同的,再开一个cnt数组,然后你们都会的

先考虑插入操作:
插入新木棍的时候我们让cnt[a]++;
当cnt[a] == 2时,我们把它插入two,注意但cnt[a] == 3时不能插入,这是一个坑。
然后当cnt[a] == 4时,我们把它插入four,同时cnt[a]清零,同时把two中的a删除。

然后再考虑删除操作:
我们先在four和two中二分找到木棍长度a,然后分类讨论:
如果two中找到了,那就将cnt[a]--; 如果cnt[a] == 1了,也就是有两个相同不成立了,就把a在two中删除。
如果two中没找到但是four中找到了,如果cnt[a] == 0,那就只有3个相同,就把a从four扔到two。
如果four和two都没找到,因为题目保证删除的木棍存在,所以只可能cnt[a] == 1,就把cnt[a]--;

最后是简单的询问操作:
如果four中有2个元素,也就是有(a a a a b b b b)的木棍,可以围成两个正方形,显然YES。
如果four中有1个元素,two中有两个元素,显然YES。
如果以上都不成立,显然NO。

上代码吧:

/*
	ID: Loxilante
	Time: 2020/08/07
	Prog: B
	Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/stdc++.h>
#define rep(i, l, r) for(register int i = l; i < r; i++)
#define hrp(i, l, r) for(register int i = l; i <= r; i++)
#define rev(i, r, l) for(register int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn> inline tn next(void) { tn k; cin>>k; return k; }
const int U = 1e6+50;
int w[U], cnt[U];
multiset<int> four, two;
inline void inst(int e)
{
	cnt[e]++;
	if (cnt[e] == 4)
	{
		four.insert(e);
		cnt[e] = 0;
		two.erase(two.lower_bound(e));
	}
	else if (cnt[e] == 2) two.insert(e);
}
signed main(void)
{
	clock_t Begin = clock();

	#ifdef JOEON
//		freopen("C:\Users\Joeon\Desktop\IN.txt", "r", stdin);
//		freopen("C:\Users\Joeon\Desktop\OUT.txt", "w", stdout);
	#endif
	
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int n = next<int>();
	rep(i, 0, n) inst(next<int>());
	int q = next<int>();
	while(q--)
	{
		char sign;
		int num;
		cin>>sign>>num;
		if (sign == '+') inst(num);
		else
		{
			bool haveTwo = 0, haveFour = 0;
			auto val = two.lower_bound(num);
			if (*val == num) haveTwo = 1;
			auto val2 = four.lower_bound(num);
			if (*val2 == num) haveFour = 1;
			if (haveTwo)
			{
				cnt[num]--;
				if (cnt[num] == 1) two.erase(two.lower_bound(num));
			}
			else if (haveFour)
			{
				if (!cnt[num]) four.erase(four.lower_bound(num)), cnt[num] = 3, two.insert(num);
				else cnt[num]--;
			}
			else cnt[num]--;
		}
		if (four.size() >= 2) cout<<"YES"<<endl;
		else if (four.size() == 1 && two.size() >= 2) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	
	clock_t InputFinished = clock();
	
	
	
	clock_t End = clock();
	
	D((double)(End-Begin)/CLOCKS_PER_SEC);
	D((double)(End-InputFinished)/CLOCKS_PER_SEC);
	
	return 0;
}
/*
inputCopy
6
1 1 1 2 1 1
6
+ 2
+ 1
- 1
+ 2
- 1
+ 2
outputCopy
NO
YES
NO
NO
NO
YES
 */

C:({color{red}{PiGeOnGuGuGu}})

原文地址:https://www.cnblogs.com/Loxilante/p/CF1392.html