2025.1.3 CW 模拟赛

题面 & 题解

T1

算法

贪心, 数学, 高精度.

思路

根据贪心, 对于两个数 \(A, B\), 我们一定会从高位到低位从大到小地填数.
考虑填法, 设 \(A\) 的前缀为 \(a\), \(B\) 的前缀为 \(b\), 将要填入的数为 \(c\).

如果将其填入 \(A\), 那么答案为 \((a \times 10 + c) \times b\).
如果将其填入 \(B\), 那么答案为 \((b \times 10 + c) \times a\).
两式相减, 得: \(c \times (b - a)\).

所以一定会将 \(c\) 放在较小的前缀后.

考虑 \(a = b\) 的情况.
先说结论, 放在剩余位数较小的数上.
以下是证明:

钦定 \(A \le B\).
对于 \(a = b\) 之前的情况, 填数必然是交替进行的, 也就是对于 \(a, b\) 的每一位, 两个填入的数是确定的.
那么 \(a + b\) 即为定值, 显然地, 和定差小积大.
而对于 \(a\), 我们可以在其尾部补 0 直至 \(A = B\), 这对答案是没有任何影响的.
根据上面的推论, 为了使两数之差更小, 将 \(c\) 填入 \(a\) 一定是不劣的.

最后因为 \(A, B \le 10^3\), 需要高精度乘.

复制代码
  • 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
#include "iostream" #include "algorithm" #include "cstring" using namespace std; constexpr int N = 1e3 + 10; int a, b; basic_string<int> t; void init() { t.clear(); scanf("%d %d", &a, &b); if (a > b) swap(a, b); for (int i = 1, x; i <= 9; ++i) { scanf("%d", &x); for (int j = 1; j <= x; ++j) t.push_back(i); } reverse(t.begin(), t.end()); } int x[N], y[N], cx, cy; int ans[N << 1]; void calculate() { cx = cy = 0; memset(ans, 0, sizeof ans); for (int i = 0; i < (a << 1); i += 2) x[++cx] = t[i], y[++cy] = t[i + 1]; for (int i = a << 1; i < (a + b); ++i) y[++cy] = t[i]; for (int i = 1, f = 0; i <= a; ++i) if (x[i] ^ y[i]) { if (x[i] > y[i] and !f) { f = 1; continue; } if (f and x[i] > y[i]) swap(x[i], y[i]); } reverse(x + 1, x + a + 1), reverse(y + 1, y + b + 1); for (int i = 1; i <= b; ++i) { for (int j = 1, tmp, nxt = 0; j <= a; ++j) { int pos = j + i - 1; tmp = y[i] * x[j]; ans[pos] += tmp % 10 + nxt, nxt = tmp / 10 + ans[pos] / 10; ans[pos] %= 10; if (j == a and nxt) { ans[++pos] = nxt; break; } } } for (int i = a + b, lead = 1; i; --i) { if (lead and !ans[i]) continue; if (ans[i] or !lead) putchar(ans[i] + '0'), lead = 0; } putchar('\n'); } void solve() { init(); calculate(); } int main() { int t; scanf("%d", &t); while (t--) solve(); return 0; }

T2

算法

数据结构, 博弈论.

思路

首先可以发现 Alice 所选的区间长度为 \(\lceil \frac{n}{2} \rceil\).

假设 Alice 第一步选择了 \(i\), 又因为 ta 只能够选择一个相邻的未被占用的点, 那么最后选择的一定是一段连续的, 并且包含 \(i\) 的区间.

此时对于 Bob, 他一定有一种方法使得 Alice 只能选择和最小的一段区间.

那么问题就转化为了枚举每一个 \(i \in [1, n]\), 找到包含位置 \(i\) 的长度为 \(\lceil \frac{n}{2} \rceil\) 的一段连续区间的最小值, 最后对于所有的最小值取 \(\max\) 即可.

实现上注意边界即可, 采用单调队列做到 \(\mathcal{O} (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
#include "iostream" #include "deque" using namespace std; constexpr int N = 5e5 + 10; #define int long long int n; int v[N], sum[N << 1]; deque<int> q; void init() { cin >> n; for (int i = 1; i <= n; ++i) cin >> v[i]; for (int i = 1; i <= 2 * n; ++i) { if (i > n) sum[i] = sum[i - 1] + v[i - n]; else sum[i] = sum[i - 1] + v[i]; } } void calculate() { int len = (n - 1) / 2 + 1, ans = -1; for (int i = 1; i + len - 1 <= n << 1; ++i) { while (!q.empty() and q.front() + len - 1 < i) q.pop_front(); while (!q.empty() and sum[i + len - 1] - sum[i - 1] <= sum[q.back() + len - 1] - sum[q.back() - 1]) q.pop_back(); q.push_back(i); if (i >= len) ans = max(ans, sum[q.front() + len - 1] - sum[q.front() - 1]); } cout << ans << '\n'; } void solve() { init(); calculate(); } signed main() { cin.tie(nullptr)->sync_with_stdio(false); solve(); return 0; }

T4

算法

分块, 树状数组.

思路

直接暴力是 \(\mathcal{O} (qnm)\) 的, 无法通过.

考虑对于环分别操作, 我们定义长度 \(> B\) 的环为大环, \(\le B\) 的为小环.
具体地, 对于大环, 维护环上前缀和, 我们在修改的时候直接打标记, 这样在查询的时候是 \(\mathcal{O}(\frac{n}{B} \log n)\) 的.
对于小环, 考虑用树状数组维护, 修改 \(\mathcal{O}(B \log n)\), 查询 \(\mathcal{O}(\log n)\).

\(B\)\(\sqrt{n \log n}\) 是最优, 总时间复杂度 \(\mathcal{O}(n \sqrt{n \log 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
  • 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
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
#include "iostream" #include "algorithm" using namespace std; #define int long long #define lowbit(x) x & -x template <class T> void read(T &x) { x = 0; char ch = getchar(); while (ch < '0' or ch > '9') ch = getchar(); while (ch >= '0' and ch <= '9') x = x * 10 + ch - 48, ch = getchar(); } void print(int x) { if (x > 9) print(x / 10); putchar(x % 10 + '0'); } constexpr int N = 1.5e5 + 10, B = 666; int n, m, Q; int a[N], tg[N]; basic_string<int> c[N], pre[N], ex; class Binary_Indexed_Tree { protected: int tr[N]; public: void update(int x, int k) { for (; x <= n; x += lowbit(x)) tr[x] += k; } int query(int x) { int ret = 0; for (; x; x -= lowbit(x)) ret += tr[x]; return ret; } int query(int l, int r) { return query(r) - query(l - 1); } } bit; void init() { read(n), read(m), read(Q); for (int i = 1, x; i <= n; ++i) read(x), c[x].push_back(i); for (int i = 1; i <= n; ++i) read(a[i]); for (int i = 1; i <= m; ++i) { if (c[i].size() <= B) { for (int x : c[i]) bit.update(x, a[x]); } else { ex.push_back(i); int tmp = 0; for (int x : c[i]) pre[i].push_back(tmp += a[x]); } } } int deal(int x, int l, int r) { l = lower_bound(c[x].begin(), c[x].end(), l) - c[x].begin(), r = upper_bound(c[x].begin(), c[x].end(), r) - c[x].begin() - 1; if (l >= (int)c[x].size() or r < l) return 0; l = (l + c[x].size() - tg[x]) % c[x].size(), r = (r + c[x].size() - tg[x]) % c[x].size(); if (l > r) return pre[x][pre[x].size() - 1] - (pre[x][l - 1] - pre[x][r]); return pre[x][r] - (l ? pre[x][l - 1] : 0); } void swp(int x) { if (c[x].empty()) return; for (int i : c[x]) bit.update(i, -a[i]); bit.update(c[x][0], a[c[x][c[x].size() - 1]]); for (int i = c[x].size() - 1; i; --i) bit.update(c[x][i], a[c[x][i - 1]]); for (int i = c[x].size() - 1; i; --i) swap(a[c[x][i]], a[c[x][i - 1]]); } void calculate() { while (Q--) { int op, l, r; read(op), read(l); if (op & 1) { read(r); int ans = bit.query(l, r); for (int x : ex) ans += deal(x, l, r); print(ans), putchar('\n'); } else { if (c[l].size() <= B) swp(l); else ++tg[l]; } } } void solve() { init(); calculate(); } signed main() { solve(); return 0; }
posted @   Steven1013  阅读(4)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开