CF 612 题解 (haven't finished -- F)

C

发现是个经典的括号匹配。

D

emm...
想到按左端点排序。一个很直接的想法,对于第 \(i\) 段区间,前 \(i-k+1\) 段区间右端点的最大值会与它的左端点构成一个小区间,最后将这些区间合并即可。值得一提的是,在这之前你要将被包含的区间删掉,不然会出现错误,这显然。(emm...考试时就是没有想到这个,以为这个做法不行)
另一个做法,类似扫描线/差分,将每个区间的左端点和右端点剥离,一个贡献为 \(1\),一个贡献为 \(-1\),从左到右扫描,若当前贡献 \(\geqslant k\),则当前合法,细节比较多。

Code (way 2)
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <set>
#define LL long long
using namespace std;
const int MAXN = 1e6 + 5;
struct Node {
	int X, Y;
	bool operator < (const Node P) const { return X != P.X ? X < P.X : Y < P.Y; }
}arr[MAXN], a[MAXN], c[MAXN << 1], v;
int n, k, tot, t, q, ans1[MAXN], ans2[MAXN], cnt, maxx[MAXN];
int Max(int x, int y) { return x > y ? x : y; }
int main() {
	scanf("%d%d", &n, &k); maxx[0] = -0x3f3f3f3f;
	for(int i = 1; i <= n; i ++) scanf("%d%d", &arr[i].X, &arr[i].Y);
	for(int i = 1; i <= n; i ++) {
		v.X = arr[i].X; v.Y = 1; c[++ tot] = v;
		v.X = arr[i].Y; v.Y = -1; c[++ tot] = v;	
	}
	sort(c + 1, c + 1 + tot); cnt = 1; c[tot + 1].X = c[0].X = ans1[cnt] = 0x3f3f3f3f;
	int las = -1;
	for(int i = 1; i <= tot; ) {
		t += (c[i].Y == 1); 
		int f = 0; f += (c[i].Y == -1);
		while(c[i + 1].X == c[i].X) i ++, t += (c[i].Y == 1), f += (c[i].Y == -1);
		if(t >= k) {
			if(ans1[cnt] == 0x3f3f3f3f) ans1[cnt] = c[i].X; q = 1;
		}
		
		las = c[i].X; i ++; t -= f;// printf("|%d|", t);
		if(t < k && q) {
			ans2[cnt] = las; cnt ++; q = 0; ans1[cnt] = 0x3f3f3f3f;
	//		printf("^%d^", cnt);
		}
	}
	if(!q) printf("%d\n", -- cnt);
	for(int i = 1; i <= cnt; i ++) printf("%d %d\n", ans1[i], ans2[i]);
	return 0;
}
/*
4 2
1 4
1 3
1 2
1 1
*/

E

(trick:一般这种排列变换问题都要考虑环,有时还要考虑奇偶。)
不妨手玩样例,我们会发现一个性质:若 \(q[i]\) 的指向为奇环,则 \(p[i]\) 的指向也为奇环,并且会转两个位置。若 \(q[i]\) 的指向为偶环,则 \(p[i]\) 的指向会形成两个同等大小的偶环。
只要看出这一点,那答案就很显然了,反着来,若最后只有一个单独的偶环,输出 \(-1\)
对于两个相同的偶环,将它们交叉统计答案,可以证明任意两个偶环组合都可以。
对于奇环,将它们的结果连起来,发现一个点要经过一个点到达它指向的节点,又因为 \(n+1\) 为偶数,所以这个点指向 \(x+(n+1)/2\)。(\(x\) 为这个点的下标)

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <set>
#include <vector>
#define LL long long
using namespace std;
const int MAXN = 1e6 + 5;
int n, a[MAXN], c[MAXN], len, ans[MAXN], b[MAXN];
bool vis[MAXN];
vector <int> v[MAXN];
int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
	for(int i = 1; i <= n; i ++) {
		if(vis[i]) continue;
		int t = i; vis[t] = 1; len = 1;
		while(!vis[a[t]]) t = a[t], vis[t] = 1, len ++;
		c[len] ++; v[len].push_back(i);
	}
	for(int i = 1; i <= n; i ++) if(i % 2 == 0 && (c[i] & 1)) { printf("-1"); return 0; }
	for(int i = 1; i <= n; i ++) {
		if(i & 1) {
			for(unsigned int j = 0; j < v[i].size(); j ++) {
				int t = v[i][j];
				for(int k = 0; k < i; k ++) b[k] = t, t = a[t];
				t = v[i][j];
				for(int k = 0; k < i; k ++) ans[t] = b[(k + i / 2 + 1) % i], t = a[t];
			}
		}
		else {
			for(unsigned int j = 0; j < v[i].size(); j += 2) {
				int t1 = v[i][j], t2 = v[i][j + 1];
				for(int k = 1; k <= i; k ++) ans[t1] = t2, ans[t2] = a[t1], t1 = a[t1], t2 = a[t2];
			}
		}
	}
	for(int i = 1; i <= n; i ++) printf("%d ", ans[i]);
	return 0;
}
posted @ 2021-07-22 15:01  Saintex  阅读(93)  评论(0编辑  收藏  举报