1. 程式人生 > 其它 >CF 612 題解 (haven't finished -- F)

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;
}