CFR-835(Div.4)解题报告

比赛传送门

D. Challenging Valleys

题意:给你一个数组,判断它是否为“山谷形”。

tourist 的做法是假想在最左边和最右边插入一个极大值(结果不变)来统一情况,然后只需要判断下凹(比左右两边都低)的位置个数。如果为 11 则正确。

By tourist

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
#include <bits/stdc++.h>

using namespace std;

#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif

int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int tt;
cin >> tt;
while (tt--) {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
int cnt = 0;
int beg = 0;
while (beg < n) {
int end = beg;
while (end + 1 < n && a[end + 1] == a[end]) {
end += 1;
}
if (beg == 0 || a[beg - 1] > a[beg]) {
if (end == n - 1 || a[end + 1] > a[end]) {
cnt += 1;
}
}
beg = end + 1;
}
cout << (cnt == 1 ? "YES" : "NO") << '\n';
}
return 0;
}

E. Binary Inversions

题意:给你一个 01 串,你最多可以将一位取反(也可以不取),问逆序对数最多为多少。

考虑预处理前缀和和后缀和,这样就可以 O(1)O(1) 得到前后缀的 01 个数。先算出总的逆序对个数,然后对于每一位,考虑取反该位的贡献即可。可以通过前后缀 01 个数很简单地求得。

By tourist

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
#include <bits/stdc++.h>

using namespace std;

#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif

int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int tt;
cin >> tt;
while (tt--) {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
vector<int> p0(n + 1);
for (int i = 0; i < n; i++) {
p0[i + 1] = p0[i] + (a[i] == 0);
}
vector<int> p1(n + 1);
for (int i = 0; i < n; i++) {
p1[i + 1] = p1[i] + (a[i] == 1);
}
long long inv = 0;
int k1 = 0;
for (int i = 0; i < n; i++) {
if (a[i] == 1) {
k1 += 1;
} else {
inv += k1;
}
}
long long ans = inv;
for (int i = 0; i < n; i++) {
auto cur = inv;
if (a[i] == 0) {
cur -= p1[i];
cur += p0[n] - p0[i + 1];
} else {
cur += p1[i];
cur -= p0[n] - p0[i + 1];
}
ans = max(ans, cur);
}
cout << ans << '\n';
}
return 0;
}

F. Quests

题意:有 nn 中物品,每中物品有一个价值,每种有无穷多个,当你拿走一个物品后 kk 秒不能拿这个物品。问 kk 最多为多少才能在 dd 秒内拿到 cc 的价值。

从大到小排序,二分答案,check 时循环选即可。有一些细节,比如 k>nk>n 时的处理等。

By tourist

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 <bits/stdc++.h>

using namespace std;

#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif

int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int tt;
cin >> tt;
while (tt--) {
int n, d;
long long c;
cin >> n >> c >> d;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a.rbegin(), a.rend());
int low = -1, high = d + 1;
while (low < high) {
int mid = (low + high + 1) >> 1;
long long sum = 0;
for (int i = 0; i < d; i++) {
int id = i % (mid + 1);
if (id < n) {
sum += a[id];
}
}
if (sum >= c) {
low = mid;
} else {
high = mid - 1;
}
}
if (low == d + 1) {
cout << "Infinity" << '\n';
} else {
if (low == -1) {
cout << "Impossible" << '\n';
} else {
cout << low << '\n';
}
}
}
return 0;
}

G. SlavicG’s Favorite Problem

题意:有一个无根树,你初始在 aa,有一个变量 xx 初始为 00,每经过一条边都会异或上该边的边权。你能到达点 bb 当且仅当 xx 到达 bb 时恰好为 00。你可以在任意时刻传送到任意位置一次(除了点 bb),问是否能到达点 bb

可以进行两遍搜索,一遍从 aa 开始但不能走 bb,一遍从 bb 开始。判断是否能存在两个点 i,ji,j,使得 iiaa 的距离和 jjbb 的距离相等(此时可以 aijba\to i\Rightarrow j\to b。用 set 维护即可。

By tourist

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
#include <bits/stdc++.h>

using namespace std;

#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif

int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int tt;
cin >> tt;
while (tt--) {
int n, a, b;
cin >> n >> a >> b;
--a; --b;
vector<vector<pair<int, int>>> g(n);
for (int i = 0; i < n - 1; i++) {
int x, y, w;
cin >> x >> y >> w;
--x; --y;
g[x].emplace_back(y, w);
g[y].emplace_back(x, w);
}
vector<int> d(n, -1);
vector<int> que(1, a);
d[a] = 0;
for (int it = 0; it < (int) que.size(); it++) {
for (auto& p : g[que[it]]) {
int u = p.first;
if (d[u] == -1 && u != b) {
que.push_back(u);
d[u] = d[que[it]] ^ p.second;
}
}
}
set<int> all;
for (int i = 0; i < n; i++) {
if (d[i] != -1) {
all.insert(d[i]);
}
}
d.assign(n, -1);
que.assign(1, b);
d[b] = 0;
for (int it = 0; it < (int) que.size(); it++) {
for (auto& p : g[que[it]]) {
int u = p.first;
if (d[u] == -1) {
que.push_back(u);
d[u] = d[que[it]] ^ p.second;
}
}
}
bool ok = false;
for (int i = 0; i < n; i++) {
if (i != b) {
if (all.find(d[i]) != all.end()) {
ok = true;
break;
}
}
}
cout << (ok ? "YES" : "NO") << '\n';
}
return 0;
}