VP Codeforces Round 879 (Div. 2)
A. Unit Array
题意:一个只有\(1, -1\)的数组,你要更改最少的数,使得数组和大于等于\(0\),且\(-1\)的个数为偶数。
记录\(1, -1\)的个数,先把它们的个数变成一样,然后如果有奇数\(-1\)就再操作一次。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
int cnt0 = std::ranges::count(a, -1);
int cnt1 = std::ranges::count(a, 1);
int ans = std::max(0, (cnt0 - cnt1 + 1) / 2);
cnt0 -= ans, cnt1 += ans;
if (cnt0 & 1) {
++ ans;
}
std::cout << ans << "\n";
}
B. Maximum Strength
题意:你要在\([L, R]\)里选两个数。它们的价值为\(|a_i - b_i|\),\(a_i\)代表第一个数在十进制下第\(i\)个数的值。求最大价值。
记\(n\)为\(R\)的长度,然后给\(L\)补前导零使得和\(R\)长度相等。设\(i\)为\(L, R\)第一个不同的位置,那么此时\(R_i > L_i\),那么两个数可以是\(R_i00000..., L_i99999999\)。答案就是\(R_i - L_i + (n - i)\times 9\)。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::string s, t;
std::cin >> s >> t;
int cnt1 = 0;
for (int i = 0; i < n; ++ i) {
cnt1 += s[i] != t[i];
}
std::ranges::reverse(s);
int cnt2 = 0;
for (int i = 0; i < n; ++ i) {
cnt2 += s[i] != t[i];
}
int ans1 = cnt1 % 2 ? cnt1 * 2 - 1 : cnt1 * 2;
int ans2 = cnt2 % 2 ? cnt2 * 2 : std::max(2, cnt2 * 2 - 1);
std::cout << std::max(0, std::min(ans1, ans2)) << "\n";
}
C. Game with Reversing
题意:\(Alice\)和\(Bob\)操作两个字符串\(s, t\)。\(Alice\)每次把一个字符串的一个字符更改为任意字符。\(Bob\)每次翻转一个字符串。如果\(s = t\)游戏结束。\(Alice\)想尽可能快结束游戏,\(Bob\)想尽可能满结束游戏。求游戏轮数。
发现\(Bob\)无论翻转哪个字符串都没什么用。只需要拿不翻转的时候记录一下不同的地方,那么\(Alice\)只需要改这些地方,如果改完某个字符串是翻转状态,那么等一个回合让\(Bob\)翻转回来就行。同时在记录一下一个字符串翻转后不同的地方,同样讨论。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::string s, t;
std::cin >> s >> t;
int cnt1 = 0;
for (int i = 0; i < n; ++ i) {
cnt1 += s[i] != t[i];
}
std::ranges::reverse(s);
int cnt2 = 0;
for (int i = 0; i < n; ++ i) {
cnt2 += s[i] != t[i];
}
int ans1 = cnt1 % 2 ? cnt1 * 2 - 1 : cnt1 * 2;
int ans2 = cnt2 % 2 ? cnt2 * 2 : std::max(2, cnt2 * 2 - 1);
std::cout << std::max(0, std::min(ans1, ans2)) << "\n";
}
D. Survey in Class
题意:给你\(n\)条线段,选两个线段\(A, B\),使得\(A\)有的点而\(B\)没有的点最多。
分三种情况,\(A\)包含\(B\)、\(B\)在\(A\)右端点左侧、\(B\)在\(A\)左端点右侧。
对于第一种情况,直接取最大长度的线段减最小长度的线段就行,因为如果最长的包含最短的,则确实是正确的,否则不包含,必定在其它两种情况里,且发现这个值比所有包含的情况都大。
对于第二种情况,可以按右端点排序,那么对于第\(i\)个线段,答案就是\(r_i - \max(l_i - 1, r_1)\),因为肯定要选右端点最小的,就是\([l_1, r_1]\),那么比较\(l_i, r_1\)的值看能取到哪里。
第三种情况同第二种情况,按左端点排序即可。
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<std::pair<int, int>> a(n);
int max = -2e9, min = 2e9;
for (auto & [l, r] : a) {
std::cin >> l >> r;
max = std::max(max, r - l + 1);
min = std::min(min, r - l + 1);
}
int ans = max - min;
std::ranges::sort(a);
for (int i = n - 1; i >= 0; -- i) {
ans = std::max(ans, std::min(a[n - 1].first, a[i].second + 1) - a[i].first);
}
std::ranges::sort(a, [&](std::pair<int, int> & a, std::pair<int, int> & b) {
return a.second < b.second;
});
for (int i = 0; i < n; ++ i) {
ans = std::max(ans, a[i].second - std::max(a[i].first - 1, a[0].second));
}
std::cout << ans * 2 << "\n";
}
E. MEX of LCM
题意:求一个最小的正整数,使得它不是\(a\)的任意一个子数组的\(lcm\)。
结论是如果固定右端点,那么所有左端点和这个右端点构成的区间的\(lcm\)不超过\(log_V\)个。其中\(v\)是值域。那么我们考虑枚举右端点,记录前面区间的所有\(lcm\),那么如果\(a_i\)和前面区间的\(lcm\)小于\(nlog_V\)则可以保留。记录哪些\(lcm\)出现过,找最小的没出现过的就行。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<i64> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
int N = 20 * n;
std::vector<int> st(N);
std::vector<i64> l;
for (int i = 0; i < n; ++ i) {
if (a[i] < N) {
l.push_back(a[i]);
}
std::vector<i64> nl;
for (auto & x : l) {
i64 lcm = std::lcm(x, a[i]);
if (lcm < N) {
nl.push_back(lcm);
}
}
std::ranges::sort(nl);
nl.erase(std::unique(nl.begin(), nl.end()), nl.end());
for (auto & x : nl) {
st[x] = 1;
}
l = nl;
}
for (int i = 1; i < N; ++ i) {
if (!st[i]) {
std::cout << i << "\n";
return;
}
}
}

浙公网安备 33010602011771号