Good Bye 2024: 2025 is NEAR

比赛链接

Problems AC Note
A. Tender Carpenter ○
B. Outstanding Impressionist ○
C. Bewitching Stargazer ○
D. Refined Product Optimality ⊕ 交换
E. Resourceful Caterpillar Sequence ⊕ game、树上计数
F. Earnest Matrix Complement
G. Naive String Splits
H. Delicate Anti-monotonous Operations
I1. Affectionate Arrays (Easy Version)
I2. Affectionate Arrays (Hard Version)

A

Code >folded
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void solve() {
int n = read();
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) a[i] = read();
for (int i = 1; i + 1 <= n; i++) {
int x = a[i];
int y = a[i + 1];
if (x < y) swap(x, y);

if (x + x > y and y + y > x) {
puts("YES");
return;
}
}
puts("NO");
}

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
32
void solve() {
int n = read();
vector<pii> a(n + 1);
for (int i = 1; i <= n; i++) {
a[i].fi = read();
a[i].se = read();
}

vector<int> buk(2 * n + 1);
vector<int> cnt(2 * n + 1);

for (int i = 1; i <= n; i++) {
auto [l, r] = a[i];
if (l != r) {
continue;
}
buk[l] = 1;
cnt[l] ++;
}
for (int i = 1; i <= 2 * n; i++) {
buk[i] += buk[i - 1];
}

for (int i = 1; i <= n; i++) {
auto [l, r] = a[i];

if ((l == r and cnt[l] == 1) or
buk[r] - buk[l - 1] != r - l + 1) putchar('1');
else putchar('0');
}
puts("");
}

C

天空中有 $n$ 颗星星,排成一排。Iris 有一架望远镜,她用它来看星星。

最初,Iris 观察线段 $[1, n]$ 中的星星,她的幸运值为 $0$ 。Iris 想要寻找她观察到的每个线段 $[l, r]$ 中间位置的星星。因此使用以下递归程序:

  • 首先,她将计算 $m = \left\lfloor \frac{l+r}{2} \right\rfloor$ 。
  • 如果线段长度(即 $r - l + 1$ )为偶数,Iris 会将其分成两个等长的线段 $[l, m]$ 和 $[m+1, r]$ ,以便进一步观察。
  • 否则,Iris 会将望远镜对准恒星 $m$ ,她的幸运值将增加 $m$ ;随后,如果为 $l \neq r$ ,Iris 将继续观察两个线段 $[l, m-1]$ 和 $[m+1, r]$ 。

Iris 有点懒。她用整数 $k$ 来定义她的懒惰程度:随着观察的进行,她不会继续观察任何长度严格小于 $k$ 的线段 $[l, r]$ 。在这种情况下,请预测她的最终幸运值。

$1 \leq k \leq n \leq 2\cdot 10^9$

注意到左子树和右子树是对称的,且差的只和当前这一层的中点以及数量有关。维护下即可

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void solve() {
int n = read();
int k = read();

auto dfs = [&](this auto&& self, int l, int r) -> pii {
int len = r - l + 1;
if (len < k) return {0, 0};
if (len == 1) return {l, 1};
int m = l + r >> 1;

if (len % 2 == 0) {
auto [sum, cnt] = self(l, m);
return {2 * sum + cnt * m, cnt * 2};
} else {
auto [sum, cnt] = self(l, m - 1);
return {m + 2 * sum + cnt * m, cnt * 2 + 1};
}
};

auto [ans, _] = dfs(1, n);
cout << ans << '\n';
}

D

  • Chris 得到两个数组 $a$ 和 $b$ ,均由 $n$ 个整数组成。
  • Iris 感兴趣的是,在对 $b$ 进行任意重新排列后, $P = \prod\limits_{i=1}^n \min(a_i, b_i)$ 的最大可能值。请注意,她只想知道 $P$ 的最大值,并且不会对 $b$ 进行任何实际的重新排列。
  • 将有 $q$ 次修改。每次修改都可以用两个整数 $o$ 和 $x$ 表示( $o$ 是 $1$ 或 $2$ , $1 \leq x \leq n$ )。如果是 $o = 1$ ,那么 Iris 会将 $a_x$ 增加 $1$ ;否则,她会将 $b_x$ 增加 $1$ 。
  • Iris 向 Chris 询问 $P$ 的最大值,共询问了 $q + 1$ 次:一次是在修改之前,另一次是在每次修改之后。
  • 由于 $P$ 可能很大,Chris 只需要计算它对 $998,244,353$ 的模数。

显然的观察是两个数组分别排序最优。而且观察到每次变化不超过 $1$,随便维护下位置就做完了。

注意不要一个一个交换,复杂度是错的。

Code
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
void solve() {
int n, m; cin >> n >> m;
vector<int> a(n), b(n);
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < n; i++) cin >> b[i];

auto c = a;
auto d = b;

std::ranges::sort(c);
std::ranges::sort(d);
Z ans = 1;
for (int i = 0; i < n; i++) {
ans *= min(c[i], d[i]);
}

cout << ans << ' ';

while (m--) {
// int opt = read(), pos = read() - 1;
int opt, x;
cin >> opt >> x;
x--;

if (opt == 1) {
a[x]++;
int i = std::lower_bound(c.begin(), c.end(), a[x]) - c.begin() - 1;
ans /= std::min(c[i], d[i]);
c[i]++;
ans *= std::min(c[i], d[i]);
}
if (opt == 2) {
b[x]++;
int i = std::lower_bound(d.begin(), d.end(), b[x]) - d.begin() - 1;
ans /= std::min(c[i], d[i]);
d[i]++;
ans *= std::min(c[i], d[i]);
}

cout << ans << " \n"[m == 0];
}
}

E

给定一棵树和一条毛毛虫 $(p, q)$ (一条树上路径),每次 N 和 A 交替移动,N 把毛毛虫的 p 端移动一步(身体也跟着动),类似地 A 把毛毛虫的 q 端移动一步,p 到叶子则 N 赢,q 到叶子则 A 赢。对满足 A 有必胜策略的初始毛毛虫计数。

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

for (int i = 1; i < n; i++) {
int u = read() - 1, v = read() - 1;
g[u].eb(v), g[v].eb(u);
}

if (n == 2) { puts("0"); return; }

int cnt = 0;
int rt = 0;
vector<int> leaf(n), sp(n);
for (int i = 0; i < n; i++) {
if (g[i].size() != 1) { rt = i; continue; }

cnt++;
leaf[i] = sp[i] = 1;
for (auto j : g[i]) sp[j] = 1;
}

int ans = cnt * (n - cnt);

vector<int> fa(n), sum(n), siz(n);
auto dfs = [&](this auto&& self, int u, int f) -> void {
fa[u] = f;
sum[u] = sp[u], siz[u] = 1;
for (auto v : g[u]) {
if (v == f) continue;
self(v, u);
sum[u] += sum[v], siz[u] += siz[v];
}
};
dfs(rt, -1);

for (int i = 0; i < n; i++) {
if (leaf[i]) continue;

if (i != rt and sp[fa[i]] and !leaf[fa[i]]) {
ans += (n - siz[i]) - (sum[rt] - sum[i]);
}

for (auto j : g[i]) {
if (j == fa[i]) continue;
if (sp[j] and !leaf[j]) ans += siz[j] - sum[j];
}
}

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

TosakaUCW

Posted on

2025-01-03

Updated on

2025-01-26

Licensed under

Comments