CodeForces 645A-645D

题外话:

今天早上打了打cf。。。就差9rating就蓝名了~

D题题目还看错了,不然就能把这四道A了…

645A:暴力

这道题就没啥好说的了吧…直接上代码了:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <iostream>
using namespace std;
char c;
char str1[10], str2[10];
bool vis[10000];
int ttt(char x) {
	if (x == 'A') return 1;
	if (x == 'B') return 2;
	if (x == 'C') return 3;
	return 0;
}
int S, T;
int q[10000];
int conv(int one, int two, int three, int four) {
	return one*1000+two*100+three*10+four;
}
void bfs(int S) {
	int head = 0;
	int tail = 1;
	q[0] = S;
	vis[S] = true;
	int now, tmp, pos;
	int one, two, three, four;
	while (head < tail) {
		now = q[head++];
		for (tmp = now, pos = 4; tmp % 10; tmp /= 10, --pos);
		tmp = now;
		four = tmp % 10; tmp /= 10;
		three = tmp % 10; tmp /= 10;
		two = tmp % 10; tmp /= 10;
		one = tmp;
		if (pos == 1) {
			tmp = conv(three, two, one, four);
			if (!vis[tmp]) {
				vis[tmp] = true;
				q[tail++] = tmp;
			}
			tmp = conv(two, one, three, four);
			if (!vis[tmp]) {
				vis[tmp] = true;
				q[tail++] = tmp;
			}
			continue;
		}
		if (pos == 2) {
			tmp = conv(two, one, three, four);
			if (!vis[tmp]) {
				vis[tmp] = true;
				q[tail++] = tmp;
			}
			tmp = conv(one, four, three, two);
			if (!vis[tmp]) {
				vis[tmp] = true;
				q[tail++] = tmp;
			}
			continue;
		}
		if (pos == 3) {
			tmp = conv(one, two, four, three);
			if (!vis[tmp]) {
				vis[tmp] = true;
				q[tail++] = tmp;
			}
			tmp = conv(three, two, one, four);
			if (!vis[tmp]) {
				vis[tmp] = true;
				q[tail++] = tmp;
			}
			continue;
		}
		if (pos == 4) {
			tmp = conv(one, four, three, two);
			if (!vis[tmp]) {
				vis[tmp] = true;
				q[tail++] = tmp;
			}
			tmp = conv(one, two, four, three);
			if (!vis[tmp]) {
				vis[tmp] = true;
				q[tail++] = tmp;
			}
			continue;
		}
	}
}
int main () {
	cin >> c;	str1[1] = c;	cin >> c;	str1[2] = c;	cin >> c;	str1[3] = c;	cin >> c;	str1[4] = c;
	cin >> c;	str2[1] = c;	cin >> c;	str2[2] = c;	cin >> c;	str2[3] = c;	cin >> c;	str2[4] = c;
	S = ttt(str1[1])*1000+ttt(str1[2])*100+ttt(str1[3])*10+ttt(str1[4]);
	T = ttt(str2[1])*1000+ttt(str2[2])*100+ttt(str2[3])*10+ttt(str2[4]);
	bfs(S);
	if (vis[T]) cout << "YES";
	else cout << "NO";
}

645B:贪心

先把k>=(n/2)的情况特判掉。

然后把前k个和后k个交换位置并翻转,例如1,2,3,4,5->5,2,3,4,1->5,4,3,2,1.

然后求一下这个序列的逆序对就可以了。

答案其实是

\[k((n-1)+(n-k))/2+k(n-2k)+k*(k-1)/2\]

化简得到

\[k(2n-2k-1)\]

注意要开long long

复杂度:\(O(1)\)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <cstdio>
#include <map>
using namespace std;
int getint() {
	int r = 0, k = 1; char c = getchar();
	for (; c < '0' || c > '9'; c = getchar())if (c == '-') k = -1;
	for (; '0' <= c && c <= '9'; c = getchar()) r = r * 10 - '0' + c;
	return r * k;
}
long long n, k, x, ans;
int main () {
	n = getint();
	k = getint();
	if (n == 1) {
		printf("0");
		return 0;
	}
	if (k >= (n/2)) {
		x = n;
		x = x * (x-1);
		x = x / 2;
		printf("%I64d", x);
		return 0;
	}
	ans = k * (n*2 - k*2 - 1);
	printf("%I64d",ans);
	return 0;
}

645C:二分

我们先无视掉”1”房间,存一个dis数组,保存的是第i个”0”的坐标(到0的距离)

然后枚举答案mid,枚举每一个位置i,如果\(mid-i…mid+i\)之间有k+1个房间,那么mid合法,否则不合法。

或者说我们在dis里找最小的x使得dis[x] >= mid-i、找最小的y使得dis[y] <= mid+i,那么检查y-x和k的大小。

复杂度:\(O(n\log^2 n)\)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <cstdio>
int getint() {
	int r = 0, k = 1; char c = getchar();
	for (; c < '0' || c > '9'; c = getchar())if (c == '-') k = -1;
	for (; '0' <= c && c <= '9'; c = getchar()) r = r * 10 - '0' + c;
	return r * k;
}
int n, k, node = 0;
char str[100100];
int dis[100100];
int lookupless(int l, int r, int x) {
	int mid;
	while (l < r) {
		mid = (l+r+1)>>1;
		if (dis[mid] > x) r = mid-1;
		else l = mid;
	}
	if (dis[l] > x) return 0;
	return l;
}
int lookupgrea(int l, int r, int x) {
	int mid;
	while (l < r) {
		mid = (l+r)>>1;
		if (dis[mid] < x) l = mid+1;
		else r = mid;
	}
	if (dis[r] < x) return 0;
	return r;
}
bool check(int x) {
	for (int i = 1; i <= node; ++i) {
		int curr = 0, f;
		if (i < node) if (f = lookupless(i+1, node, dis[i]+x)) curr += (f - i);
		if (2 <= i) if (f = lookupgrea(1, i-1, dis[i]-x)) curr += (i - f);
		if (curr >= k) return true;
	}
	return false;
}
int main () {
	n = getint(); k = getint();
	scanf("%s", str);
	for (int i = 0; i < n; ++i)
		if (str[i] == '0') dis[++node] = i;
	int l = 1, r = n, mid;
	while (l < r) {
		mid = (l + r) >> 1;
		if (check(mid)) r = mid;
		else l = mid+1;
	}
	printf("%d", r);
}

645D:二分

枚举答案,check过程判断一下拓扑图是否唯一即可。

赛后卢爷表示这题\(O(m)\)可做,先求出拓扑序,然后\(O(m\)扫描每条边,如果这条边是“关键的”,记录一下此时边id。这样我们找出n-1条关键链就可以了。

复杂度(比赛时我写的):\(O(n\log m)\)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <cstdio>
int getint() {
	int r = 0, k = 1; char c = getchar();
	for (; c < '0' || c > '9'; c = getchar())if (c == '-') k = -1;
	for (; '0' <= c && c <= '9'; c = getchar()) r = r * 10 - '0' + c;
	return r * k;
}
int n, m;
const int maxn = 100100;
int A[maxn], B[maxn];
int sta[maxn], slen = 0;
int rd[maxn];
bool insta[maxn];
struct edge_type {
	int to, next;
} edge[maxn<<1];
int h[maxn], cnte;
void ins(int u, int v) {
	edge[++cnte].to = v;
	edge[cnte].next = h[u];
	h[u] = cnte;
}
void build(int x) {
	cnte = 1;
	for (int i = 1; i <= n; ++i) h[i] = rd[i] = 0;
	for (int i = 1; i <= x; ++i) { ins(A[i], B[i]); ++rd[B[i]]; }
}
bool check(int x) {
	build(x);
	slen = 0;
	for (int i = 1; i <= n; ++i) { insta[i] = false; if (rd[i] == 0) { sta[slen++] = i; insta[i] = true; } }
	int now;
	while (slen) {
		if (slen != 1) return false;
		now = sta[--slen];
		for (int i = h[now]; i; i = edge[i].next) {
			if (insta[edge[i].to]) return false;
			--rd[edge[i].to];
			if (!rd[edge[i].to]) {
				sta[slen++] = edge[i].to;
				insta[edge[i].to] = true;
			}
		}
	}
	return true;
}
int main () {
	n = getint(); m = getint();
	for (int i = 1; i <= m; ++i) { A[i] = getint(); B[i] = getint(); }
	int l = 1, r = m, mid;
	while (l < r) {
		mid = (l+r)>>1;
		if (check(mid)) r = mid;
		else l = mid+1;
	}
	if (check(r)) printf("%d", r);
	else printf("-1");
	return 0;
}