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
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
using namespace std;
constexpr int N = 5e5 + 10;
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
using namespace std;
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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步