Codeforces Round 1048 (Div. 1)

Codeforces Round 1048 (Div. 1)

Date 2025.09.08

A B C1 C2 D E1 E2 F
O O O O Ø

D - Antiamuny and Slider Movement

首先一个 trick 是,你可以把求和转化成求期望(对 $q!$ 种操作序列求平均),再乘上 $q!$。

这样的话,你就可以枚举每个滑块,再枚举最后决定滑块位置的那一次操作,统计贡献。

还有一个 trick 是,因为滑块不会越过另外一个滑块,相对位置是不变的,所以可以让 a[i] -= i; b[i].x -= b[i].id; 转化成相对位置。

令 $b_i = a_i - i$,这样 $b_i$ 是单调不降的。且原来 $a_i \le a_{i + 1} - 1$ 的约束变成了 $b_i \le b_{i + 1}$。

$a_i \leftarrow x$ 对应为 $b_i \leftarrow x - i$。

并且,对于左右滑块位置的更新也从加减操作变成了取 min/max 操作:

  • 往左一侧($j<i$):$a^\prime_j=\min(a_j,a^\prime_{j+1}-1) \Longrightarrow b^\prime_j=\min(b_j,b^\prime_{j+1}).$
  • 往右一侧($j>i$):$a^\prime_j=\max(a_j,a^\prime_{j-1}+1) \Longrightarrow b^\prime_j=\max(b_j,b^\prime_{j-1}).$

因此有一个推论,若只看对第 $i$ 个滑块的影响,把第 $id$ 个(目标 $x$)作用一次对 $b_i$ 的“净效果”是
$$
b_i \leftarrow
\begin{cases}
\max(b_i,x), & id<i。\
x, & id=i。 \
\min(b_i,x), & id>i。 \
\end{cases}
$$

那么回到之前说的,枚举滑块 $[i, x]$,枚举最后一个决定位置的操作 $[j, y]$。假如你现在维护了一个可能对当前滑块最终位置有影响的集合 $S$
根据定义,$S$ 只有可能是 $j > i$ 且 $y < x$ 或者 $j < i$ 且 $y \ge x$ 的元素
并且最终是操作 $[j, y]$ 决定了 滑块 $i$ 的最终位置。
那么需要满足的条件是:

  • $j$ 在 $S$ 中是最后一个元素
  • 倒数第二个必须是 $j > i$ 且 $y < x$ 的,因为不能是 $j < i$ 且 $y \ge x$。

只需要维护这两种的数量,然后算算组合数即可。

时间复杂度 $O(nq)$

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
void solve() {
int n, m, q;
cin >> n >> m >> q;

vector<int> a(n);
for (auto &x : a) cin >> x;

vector<pii> b(q);
for (auto &[id, x] : b) cin >> id >> x;

for (int i = 0; i < n; i++) a[i] -= i;
for (int i = 0; i < q; i++) {
auto &[id, x] = b[i];
id--, x -= id;
}

ranges::sort(b, [&](auto i, auto j) {
return i.second < j.second;
});

for (int i = 0; i < n; i++) {
int f = 0;
for (auto [id, x] : b) {
if (id <= i and x >= a[i]) f = 1;
if (id >= i and x < a[i]) f = 1;
}
if (!f) {
cout << Z(a[i] + i) * comb.fac(q) << " \n"[i == n - 1];
continue;
}

Z res = 0;
int cl = 0, cr = 0;
for (auto [id, x] : b) if (id <= i) cr++;

for (auto [id, x] : b) {
if (id <= i) cr--;

Z fp = x + i;
Z denom = comb.inv(cl + cr + 1) * comb.inv(cl + cr);

if (id == i) {
res += fp / (cl + cr + 1);
} else if (id < i) {
if (cl == 0 and cr == 0 and a[i] <= x) {
res += fp;
} else {
res += fp * cl * denom;
}
} else {
if (cl == 0 and cr == 0 and a[i] > x) {
res += fp;
} else {
res += fp * cr * denom;
}
}

if (id >= i) cl++;
}

cout << res * comb.fac(q) << " \n"[i == n - 1];
}
}

C1 & C2 - Maple and Tree Beauty

01 背包即可,bitset 优化一下

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

vector<vector<int>> g(n + 1);
vector<int> p(n + 1);
for (int i = 2; i <= n; i++) {
p[i] = read();
g[p[i]].eb(i);
}

vector<int> dep(n + 1);

dep[1] = 1;
auto dfs = [&](this auto&& dfs, int u) -> void {
for (int v : g[u]) {
dep[v] = dep[u] + 1;
dfs(v);
}
};
dfs(1);

int dmin = inf;
for (int i = 1; i <= n; i++) {
if (g[i].empty()) {
dmin = min(dmin, dep[i]);
}
}

vector<int> cnt(dmin + 1, 0);
for (int i = 1; i <= n; i++) {
if (dep[i] <= dmin) cnt[dep[i]]++;
}

vector<int> cost;
for (int d = 1; d <= dmin; d++) cost.eb(cnt[d]);
ranges::sort(cost);

const int MAXK = 200000 + 5;
bitset<MAXK> dp;
dp[0] = 1;

int tot = 0;
int ans = 0;
int m = cost.size();

for (int i = 0; i < m; i++) {
int w = cost[i];
tot += w;

if (w <= 200000) dp |= (dp << w);

int L = max(0LL, tot - (n - k));
int R = min(k, tot);
bool f = 0;
for (int s = L; s <= R; s++) {
if (dp.test(s)) { f = 1; break; }
}
if (f) ans = i + 1;
}

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

B - Antiamuny Wants to Learn Swap

check 一下是否存在 3 2 1 的子序列

如果是任意的话,还需 check 4 3 1 2

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

vector<int> a(n + 1);
for (int i = 1; i <= n; i++) a[i] = read();

vector<int> l(n + 1, 0);
{
vector<int> st;
st.reserve(n);
for (int i = 1; i <= n; i++) {
while (!st.empty() and a[st.back()] <= a[i]) st.pop_back();
l[i] = st.empty() ? 0 : st.back();
st.eb(i);
}
}
vector<int> r(n + 1, n + 1);
{
vector<int> st;
st.reserve(n);
for (int i = n; i >= 1; --i) {
while (!st.empty() and a[st.back()] >= a[i]) st.pop_back();
r[i] = st.empty() ? n + 1 : st.back();
st.eb(i);
}
}

vector<int> f(n + 1, n);
for (int i = 1; i <= n; i++) {
if (l[i] != 0 && r[i] != n + 1) {
f[l[i]] = min(f[l[i]], r[i] - 1);
}
}
for (int i = n - 1; i >= 1; i--) {
f[i] = min(f[i], f[i + 1]);
}

while (q--) {
int l = read(), r = read();
if (r <= f[l]) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
}

A - Cake Assignment

反着来的话,会发现操作是唯一的

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

int t = 1LL << (k + 1);
int half = 1LL << k;
int p = x;

vector<int> ans;
while (p != half) {
if (p < half) {
ans.eb(1);
p <<= 1;
} else {
ans.eb(2);
p = (p << 1) - t;
}
}

int n = ans.size();
cout << n << "\n";
ranges::reverse(ans);
for (auto x : ans) cout << x << " ";
cout << "\n";
}
Author

TosakaUCW

Posted on

2025-09-09

Updated on

2025-09-10

Licensed under

Comments