Codeforces Round 973 (Div. 2)
Sol CF2013
A
每次最多操作 \(\min(x, y)\),故答案为 \(\lceil\frac{n}{\min(x, y)}\rceil\)。
#include <bits/stdc++.h>
using namespace std;
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
#define IOS
#define MULTI
void solve() {
int n, x, y;
cin >> n >> x >> y;
x = min(x, y);
cout << (n + x - 1) / x << '\n';
}
int main() {
#ifdef IOS
ios::sync_with_stdio(false);
cin.tie(nullptr);
#endif
#ifdef MULTI
int TestCase = 1;
for (cin >> TestCase; TestCase--;) solve();
#else
solve();
#endif
return 0;
}
B
若 \(i < j < k\),\(j\) 把 \(i\) 打败,\(k\) 把 \(j\) 打败,最后的答案为 \(a_k + a_i - a_j\)。
可知 \(n\) 必须保留,前面所有都必须被某个人打败。
又 \(n - 1\) 必须被 \(n\) 打败,即答案一定有 \(a_n - a_{n-1}\)。
那么只需要让 \(n - 1\) 先打败 \([1, n - 2]\),就可构造最大答案 \(a_1 + a_2 + \cdots + a_{n - 2} - a_{n - 1} + a_n\)。
#include <bits/stdc++.h>
using namespace std;
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
#define IOS
#define MULTI
i < j < k
j eat i
k eat j
n + 1 + 2 + ... + (n - 2) - (n - 1)
void solve() {
int n;
cin >> n;
vector<int> a(n);
for (int &x : a)
cin >> x;
// sort(begin(a), end(a));
i64 sum = 0;
for (int i = 0; i < n; ++i)
if (i != n - 2) sum += a[i];
cout << sum - a[n - 2] << '\n';
}
int main() {
#ifdef IOS
ios::sync_with_stdio(false);
cin.tie(nullptr);
#endif
#ifdef MULTI
int TestCase = 1;
for (cin >> TestCase; TestCase--;) solve();
#else
solve();
#endif
return 0;
}
C
首先考虑从前缀或后缀开始猜,那么每次只需要一个询问就能确定下一个字符。
考虑怎么搞到前缀/后缀。不妨一开始先随便问一个字符,然后不断在这个字符后面添加 0/1,再询问,就可以得到一个极长的存在于原串 \(s\) 中的子串 \(t\)。
为什么称为极长?因为 \(t\) 后面无论添加 0 还是 1 都无法更长。那么,\(t\) 就是一个后缀!并且这个 \(t\) 只是后缀!因为假设 \(t\) 出现在了 \(s\) 中一个非后缀的位置,显然 \(t\) 不是极长的(还可以往后拓展)。
那么不断在 \(t\) 前面加 0/1 即可得到答案。注意处理边界防止询问次数过多,可参考代码。
#include <bits/stdc++.h>
using namespace std;
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
#define IOS
#define MULTI
void solve() {
int n;
cin >> n;
auto ask = [=](string s) -> int {
int judge;
cout << "? " << s << endl;
cin >> judge;
return judge;
};
auto guess = [=](string s) -> void {
cout << "! " << s << endl;
return;
};
auto sol = [=](string s) {
for (int len = 2; len <= n; ++len) {
s.push_back('0');
if (ask(s)) continue;
else {
s[len - 1] = '1';
if (ask(s)) continue;
else {
s.pop_back();
break;
}
}
}
return s;
};
if (!ask("0")) {
string res;
for (int i = 1; i <= n; ++i)
res.push_back('1');
guess(res);
} else {
string suf = sol("0");
while (int(suf.size()) < n) {
suf = '0' + suf;
if (!ask(suf)) suf[0] = '1';
}
guess(suf);
}
}
int main() {
#ifdef IOS
ios::sync_with_stdio(false);
cin.tie(nullptr);
#endif
#ifdef MULTI
int TestCase = 1;
for (cin >> TestCase; TestCase--;) solve();
#else
solve();
#endif
return 0;
}
D
看完题目发现可以模拟。从前往后处理,每次新加入一个数,我们考虑尽可能把这个数调大。当然如果这个数是 \(\max\) 就不用调了,也没办法调(所以算法是正确的)。
如何尽可能调大?就是找前面的最大值,将其减小,添加到当前这个数。如果开个 map,就可以 \(O(\log n)\) 找到这样的数,调完当前数后,把当前数塞回去。均摊一下时间复杂度 \(O(n\log n)\)。
#include <bits/stdc++.h>
using namespace std;
using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
#define IOS
#define MULTI
void solve() {
int n;
cin >> n;
vector<i64> a(n);
for (auto &x : a)
cin >> x;
map<i64, int> mp;
mp[0] = 0;
// 假设 val -= k
// 1. k <= (val - a[i]) / (cnt + 1)
// 2. k <= val - sev
// cout << "n = " << n << '\n';
for (int i = 0; i < n; ++i) {
while (int(mp.size()) > 1) {
auto [val, cnt] = *rbegin(mp);
mp.erase(val);
i64 sev = rbegin(mp) -> first;
i64 k = min(val - sev, (val - a[i]) / (cnt + 1));
if (k < 0) k = 0;
a[i] += cnt * k;
mp[val - k] += cnt;
if (k == 0 || val == 0) break;
}
// 假设 cnt -= k
// 1. k < cnt
// 2. a[i] + cnt < val
while (int(mp.size()) > 1) {
auto [val, cnt] = *rbegin(mp);
if (val == 0) break;
mp.erase(val);
// i64 sev = rbegin(mp) -> first;
i64 k = min((i64)cnt, val - a[i]) - 1;
if (k < 0) k = 0;
a[i] += k;
mp[val] += cnt - k;
mp[val - 1] += k;
if (k == 0) break;
}
mp[a[i]] += 1;
// for (auto [val, cnt] : mp)
// for (int i = 0; i < cnt; ++i)
// cout << val << " ";
// cout << '\n';
}
i64 mn = 1e18, mx = -mn;
for (auto [v, c] : mp)
if (c) {
mn = min(mn, v);
mx = max(mx, v);
}
cout << mx - mn << '\n';
}
int main() {
#ifdef IOS
ios::sync_with_stdio(false);
cin.tie(nullptr);
#endif
#ifdef MULTI
int TestCase = 1;
for (cin >> TestCase; TestCase--;) solve();
#else
solve();
#endif
return 0;
}
E/F
不会。
本文来自博客园,作者:lingfunny,转载请注明原文链接:https://www.cnblogs.com/lingfunny/p/18424527