Codeforces Round 989 (Div. 1 + Div. 2)

构造 Round

Rayan Programming Contest 2024 - Selection (Codeforces Round 989, Div. 1 + Div. 2)

Problems AC
A. King Keykhosrow’s Mystery ○
B. Rakhsh’s Revival ○
C. Trapped in the Witch’s Labyrinth ○
D. Darius’ Wisdom ⊕
E. Permutations Harmony ⊕
F1. Khayyam’s Royal Decree (Easy Version)
F2. Khayyam’s Royal Decree (Hard Version)
G1. Simurgh’s Watch (Easy Version)
G2. Simurgh’s Watch (Hard Version)
H. Rayan vs. Rayaneh

A

听说有人暴力枚举被叉了,乐

Code >folded
1
2
3
4
5
void solve() {
int a = read();
int b = read();
cout << a * b / std::__gcd(a, b) << '\n';
}

B

Code >folded
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
void solve() {
int n = read();
int m = read();
int k = read();

string s;
cin >> s;

int ans = 0;

for (int i = 0; i < n; ) {
if (s[i] == '1') { i++; continue; }
int j = i;
int cnt = 0;
while (s[j] == '0' and j < n) {
cnt++;
if (cnt == m) {
cnt = 0;
j += k;
ans++;
break;
}
j++;
}
i = (j == i) ? i + 1 : j;

// cout << i << '\n';
}

cout << ans << '\n';
}

C

Code >folded
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
void solve() {
int n = read();
int m = read();

vector<string> s(n);
for (int i = 0; i < n; i++) {
cin >> s[i];
}

vector bad(n, vector<int>(m));

std::queue<pii> q;

for (int i = 0; i < n; i++) {
if (s[i][0] == 'L') {
bad[i][0] = 1;
q.ep(i, 0);
}
if (s[i][m - 1] == 'R') {
bad[i][m - 1] = 1;
q.ep(i, m - 1);
}
}
for (int i = 0; i < m; i++) {
if (s[0][i] == 'U') {
bad[0][i] = 1;
q.ep(0, i);
}
if (s[n - 1][i] == 'D') {
bad[n - 1][i] = 1;
q.ep(n - 1, i);
}
}

while (!q.empty()) {
auto [x, y] = q.front();
q.pop();

if (x > 0 and !bad[x - 1][y] and s[x - 1][y] == 'D') {
bad[x - 1][y] = 1;
q.ep(x - 1, y);
}
if (x < n - 1 and !bad[x + 1][y] and s[x + 1][y] == 'U') {
bad[x + 1][y] = 1;
q.ep(x + 1, y);
}
if (y > 0 and !bad[x][y - 1] and s[x][y - 1] == 'R') {
bad[x][y - 1] = 1;
q.ep(x, y - 1);
}
if (y < m - 1 and !bad[x][y + 1] and s[x][y + 1] == 'L') {
bad[x][y + 1] = 1;
q.ep(x, y + 1);
}
}

int ans = 0;

for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (!bad[i][j] and s[i][j] != '?') ans++;
else if (!bad[i][j]) {
bool f = 1;
if (i > 0) f &= bad[i - 1][j];
if (i < n - 1) f &= bad[i + 1][j];
if (j > 0) f &= bad[i][j - 1];
if (j < m - 1) f &= bad[i][j + 1];
if (!f) ans++;
}
}
}

cout << ans << '\n';
}

D

重写了一遍就过了,,,,做法是从右往左确定位置,次数容易证明是正确的。

Code >folded
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
void solve() {
int n = read();

vector<int> a(n + 1);
vector<int> cnt(3);

std::set<int> s[3];

for (int i = 1; i <= n; i++) {
a[i] = read();
s[a[i]].ep(i);
}

int p1 = s[0].size(), p2 = s[0].size() + s[1].size();

vector<pii> ans;

for (int i = n; i > p2; i--) {
if (a[i] == 2) continue;
if (a[i] == 0) {
int j = *s[1].begin();

ans.eb(i, j);
swap(a[i], a[j]);

s[0].erase(i);
s[1].erase(j);
s[0].ep(j);
s[1].ep(i);
}

if (a[i] == 1) {
int j = *s[2].begin();

ans.eb(i, j);
swap(a[i], a[j]);

s[1].erase(i);
s[2].erase(j);
s[1].ep(j);
s[2].ep(i);
}
}

for (int i = p2; i > p1; i--) {
if (a[i] == 1) continue;
if (a[i] == 0) {
int j = *s[1].begin();

ans.eb(i, j);
swap(a[i], a[j]);

s[0].erase(i);
s[1].erase(j);
s[0].ep(j);
s[1].ep(i);
}
}

bool flag = 1;
for (int i = 1; i < n; i++) {
if (a[i] > a[i + 1]) {
flag = 0;
break;
}
}

assert(flag);
assert(ans.size() <= n);

cout << ans.size() << '\n';
for (auto [i, j] : ans) {
cout << i << " " << j << '\n';
}
}

E

总和是 $(1 + n) * n / 2 * k$

一列是 $(1 + n) * k / 2$

因此 $(n + 1)$ 和 $k$ 同时是奇数时是无解的。

平均到每个 $k$ 就是 $(1 + n) / 2$。

因此有个想法是让两个排列配对,使得这两个排列每一列加起来是 $n + 1$。

发现这样能构造出最多的方案。前提是 $n$ 是偶数。

假如 $n$ 是奇数呢?考虑构造一个 3 行的,然后转化成偶数,用 2 行去凑。

发现其中一种构造是

1
2
3
1 2 3 4 5
3 4 5 1 2
5 3 1 4 2
1
2
3
1 2 3 4 5 6 7
4 5 6 7 1 2 3
(n + 1) * 3 / 2 - a[i] - b[i]

思路和代码实现是学习的 这个视频。

Code >folded
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
void solve() {
int n = read();
int k = read();

// n 0 k 1
vector<vector<int>> ans;

auto fill = [&](std::set<vector<int>> forbid) {
vector<int> p(n), q(n);
std::iota(p.begin(), p.end(), 1);

while (ans.size() < k) {
for (int i = 0; i < n; i++) {
q[i] = n + 1 - p[i];
}

if (p >= q) {
break;
}

if (forbid.contains(p) or forbid.contains(q)) {
// continue;
} else {
ans.eb(p);
ans.eb(q);
}

std::next_permutation(p.begin(), p.end());
}
};

auto go = [&]() -> bool {
if ((n + 1) % 2 and k % 2) {
return 0;
}
if (n == 1) {
if (k == 1) {
ans.eb(vector<int>(1, 1));
return 1;
}
return 0;
}

if (k % 2 == 0) {
fill({});
return ans.size() == k;
}
// k is odd
if (k == 1) {
return 0;
}

vector<int> a(n);
vector<int> b(n);
vector<int> c(n);
for (int i = 0; i < n; i++) {
a[i] = i + 1;
b[i] = (i + n / 2) % n + 1;
c[i] = (n + 1) * 3 / 2 - a[i] - b[i];
}

std::set<vector<int>> forbid;
forbid.ep(a);
forbid.ep(b);
forbid.ep(c);
ans.eb(a);
ans.eb(b);
ans.eb(c);
fill(forbid);
return ans.size() == k;
};

if (go()) {
cout << "YES\n";
for (auto x : ans) {
for (auto y : x) {
cout << y << " ";
}
cout << "\n";
}
} else {
cout << "NO\n";
}
}

Author

TosakaUCW

Posted on

2024-12-02

Updated on

2024-12-09

Licensed under

Comments