[ABC313] C~E + G 题解
[ABC313] C~E 题解
C - Approximate Equalization 2
让所有的数字都尽量接近平均数,先算出平均数,然后把所有数字分成两份,一份要加,一份要减,因为平均数有余数,余数肯定给最大的几个,所以这样计算总共需要加减多少个,然后在加减里面取 \(\max\) 即可。
时间复杂度:\(O(n\log n)\)
#include <algorithm>
#include <iostream>
#define int long long
using namespace std;
const int N = 2e5 + 10;
int n, a[N];
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
int s = 0, r;
for(int i = 1; i <= n; i ++)
cin >> a[i], s += a[i];
r = s % n, s /= n;
sort(a + 1, a + n + 1);
int cnt1 = 0, cnt2 = 0;
for(int i = 1; i <= n - r; i ++) {
if(a[i] <= s)
cnt1 += s - a[i];
else cnt2 += a[i] - s;
}
for(int i = n - r + 1; i <= n; i ++) {
if(a[i] <= s + 1)
cnt1 += s - a[i];
else cnt2 += a[i] - s - 1;
}
cout << max(cnt1, cnt2) << '\n';
return 0;
}
D - Odd or Even
设前 \(k - 1\) 个数的和的奇偶性为 \(x\),则使用 \(n - k + 1\) 次询问得到 \(A_{k\sim n}\) 异或 \(x\) 的奇偶性。
考虑得到 \(A_{1\sim k - 1}\) 异或 \(x\) 的奇偶性,考虑用别的位置的贡献消除 \(A_i\) 的贡献,由于 \(k < n\) 所以 \(A_{n - 1}\) 的贡献已经被算过了,不妨用 \(A_{n - 1}\) 消除贡献,可以考虑如下构造:a[n - 1] xor a[n] xor query
,query
查询 \(\{j\in{[1, k -1]\wedge j\ne i}\vee j = [n - 1, n]\}\),这样就可以得到 \(A_i \oplus x\) 的奇偶性,由于 \(k\) 是奇数,所以前 \(k\) 个数的奇偶异或 \(x\) 的异或和等于原值的异或和异或 \(x\),也就是 \(A_k\),将 \(A_k \oplus x\) 与 \(A_k\) 比较可得出 \(x\) 的奇偶性,然后全部数字异或 \(x\) 消除它的影响就是原数组了。
时间复杂度:\(O(nk)\)。
// Problem: D - Odd or Even
// Contest: AtCoder - AtCoder Beginner Contest 313
// Author: Moyou
// Copyright (c) 2023 Moyou All rights reserved.
// Date: 2023-08-05 20:27:06
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
const int N = 2e5 + 10;
int n, k;
bool a[N];
int t[N], tmp[N], x;
int ask() {
memcpy(tmp, t, sizeof t);
sort(tmp + 1, tmp + k + 1);
cout << "? ";
for(int i = 1; i <= k; i ++) cout << tmp[i] << ' ';
int x;
cout << '\n' << flush;
cin >> x;
return x;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> k;
iota(t + 1, t + k + 1, 1);
for(int i = k; i <= n; i ++) {
t[k] = i;
a[i] = ask();
}
for(int i = 1; i < k; i ++) {
t[i] = n - 1;
a[i] = a[n] ^ ask() ^ a[n - 1];
t[i] = i;
}
int sum = 0;
for(int i = 1; i <= k; i ++) sum += a[i];
sum &= 1;
sum ^= a[k];
for(int i = 1; i <= n; i ++)
a[i] ^= sum;
cout << "! ";
for(int i = 1; i <= n; i ++) cout << a[i] << ' ';
cout << '\n' << flush;
return 0;
}
E - Duplicate
首先观察到如果有连续两个数字大于 \(2\),则会无限循环,这样会让其中一个数字无限复制。
所以假设第 \(i\) 个位置之后的都已经被消除了,使用了 \(step\) 步,现在要消除第 \(i\) 个位置的字符,则它身后的字符会复制 \((step + 1)(s_i - 1)\) 次,这样迭代更新 \(step\) 直到只剩一个字符为止。
时间复杂度:\(O(n)\)。
int step = 0;
for(int i = n - 1; i; i --) {
if(s[i] >= '2' && s[i - 1] >= '2') return cout << -1 << '\n', 0;
step ++, step %= mod, step = ((s[i] - '0' - 1) * step % mod + step) % mod;
}
G - Redistribution of Piles
在一轮操作内,一定是先做连续的一段 A 操作,再做连续的一段 B 操作。
因为如果先做了 B 操作之后突然做 A 操作相当于这两次什么都没干,反之亦然。
所以暴力的思路就是枚举做了多少次 A 操作,然后可以计算出最多做多少次 B 操作。
这样是 \(O(V + n\log n)\) 的,显然会超时。
考虑化简式子。
最后一行是类欧的经典形式 \(\sum \lfloor \dfrac{ai+b}c \rfloor\),然后这题就做完了,时间复杂度:\(O(n\log V)\)。
由于博主太菜不会类欧,所以使用了
atcoder
库下的floor_sum
。
// Problem: G - Redistribution of Piles
// Contest: AtCoder - AtCoder Beginner Contest 313
// URL: https://atcoder.jp/contests/abc313/tasks/abc313_g
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// Author: Moyou
// Copyright (c) 2023 Moyou All rights reserved.
// Date: 2023-08-07 18:09:55
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <set>
#include "atcoder/math.hpp"
#include "atcoder/modint.hpp"
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
using mint = atcoder::modint998244353;
using ll = long long;
ll n, a[N];
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i ++)
cin >> a[i];
sort(a + 1, a + n + 1);
mint ans = a[1] + 1;
ll sum = n * a[1];
for(int i = 2; i <= n; i ++) {
ll k = n - i + 1;
ans += atcoder::floor_sum(a[i] + 1, n, k, -k * a[i - 1] + sum) - atcoder::floor_sum(a[i - 1] + 1, n, k, -k * a[i - 1] + sum); // atcoder 库的类欧是 0~n-1 的,所以要 +1
sum += (a[i] - a[i - 1]) * (n - i + 1);
ans += a[i] - a[i - 1];
}
cout << ans.val() << '\n';
return 0;
}