「题解」Codeforces Round 905 (Div. 3)
before
终于有一篇题解是一次性更所有题的了。
A. Morning
Problem
Sol&Code
根据题意模拟即可。
#include <bits/stdc++.h>
typedef long long ll;
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
int T;
int main() {
scanf("%d", &T);
while (T--) {
std::string s;
std::cin >> s;
int now = 1, ans = 1;
for (int i = 0; i < 4; ++i) {
if (now == s[i] - '0') ++ans;
else {
ans += std::abs(((s[i] - '0') ? (s[i] - '0') : 10) - (now ? now : 10)) + 1;
now = s[i] - '0';
}
}
printf("%d\n", ans - 1);
}
return 0;
}
B. Chemistry
Problem
Sol&Code
回文与否只与字符出现次数有关。
从长为 \(n\) 的字符串中删去 \(k\) 个字符,若最后的串长度 \((n - k)\) 为奇数,首先需要原串中出现奇数次的字符的数量不超过 \(k + 1\),若最后的串长度 \((n - k)\) 为奇数,需要原串中出现奇数次的字符的数量不超过 \(k\)。保证出现奇数次的字符数量合适后只需要剩下的删除字符次数为偶数即可。分类讨论可得,只要满足了前者,后者就得到了保证。(真神奇)
#include <bits/stdc++.h>
typedef long long ll;
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
int T, n, k, odd, cnt[648];
std::string s;
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d %d", &n, &k);
std::cin >> s;
for (int i = 'a'; i <= 'z'; ++i) cnt[i] = 0;
for (int i = 0; i < n; ++i) ++cnt[s[i]];
bool okay = true;
if ((n - k) & 1) {
odd = 0;
for (int i = 'a'; i <= 'z'; ++i) {
if (cnt[i] & 1) ++odd;
}
if (odd - 1 > k) okay = false;
} else {
odd = 0;
for (int i = 'a'; i <= 'z'; ++i) {
if (cnt[i] & 1) ++odd;
}
if (odd > k) okay = false;
}
puts(okay ? "YES" : "NO");
}
return 0;
}
C.Raspberries
Problem
Sol&Code
\(k\) 只有四种情况。
对每种情况分类讨论凑出因子的情况即可。
#include <bits/stdc++.h>
#define N 100001
typedef long long ll;
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
int T, n, k, a[N];
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
if (k == 2) {
int ans = 1;
for (int i = 1; i <= n; ++i) {
if (!(a[i] & 1)) ans = 0;
}
printf("%d\n", ans);
}
if (k == 3) {
int ans = 2;
for (int i = 1; i <= n; ++i) {
if (a[i] % 3 == 0) { ans = 0; break; }
if (a[i] % 3 == 2) { ans = 1; }
}
printf("%d\n", ans);
}
if (k == 4) {
int cnt = 0, ans = 3;
for (int i = 1; i <= n; ++i) {
if (a[i] % 4 == 0) { ans = 0; break; }
if (a[i] % 4 == 3) { ans = min(ans, 1); }
if (a[i] % 4 == 2) { ans = min(ans, 2); }
if (a[i] % 4 == 1) { ans = min(ans, 3); }
if (a[i] % 2 == 0) ++cnt;
}
if (cnt >= 2) printf("%d\n", 0);
if (cnt == 1) printf("%d\n", min(1, ans));
if (cnt == 0) printf("%d\n", min(2, ans));
}
if (k == 5) {
int ans = 4;
for (int i = 1; i <= n; ++i) {
if (a[i] % 5 == 0) { ans = 0; break; }
if (a[i] % 5 == 2) { ans = min(ans, 3); }
if (a[i] % 5 == 3) { ans = min(ans, 2); }
if (a[i] % 5 == 4) { ans = min(ans, 1); }
}
printf("%d\n", ans);
}
}
return 0;
}
D. In Love
Problem
Sol&Code
不相交即满足最小的右端点的位置小于最大的左端点的位置
multiset
可以满足插入、删除、有序的需求
#include <bits/stdc++.h>
#define N 100001
#define fir first
#define sec second
typedef long long ll;
typedef std::pair<int, int> pii;
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
int T;
class Pair {
public:
Pair(int x, int y) : a(x), b(y) {}
int a, b;
};
bool cmp1(const Pair& p1, const Pair& p2) {
if (p1.a == p2.a) return p1.b < p2.b;
return p1.a < p2.a;
}
bool cmp2(const Pair& p1, const Pair& p2) {
if (p1.b == p2.b) return p1.a < p2.a;
return p1.b < p2.b;
}
std::multiset<Pair, decltype(cmp1)*> s1(cmp1);
std::multiset<Pair, decltype(cmp2)*> s2(cmp2);
int main() {
scanf("%d", &T);
while (T--) {
getchar();
char ch;
int a, b;
ch = getchar();
scanf("%d %d", &a, &b);
if (ch == '+') {
s1.insert(Pair(a, b));
s2.insert(Pair(a, b));
} else {
s1.erase(s1.find(Pair(a, b)));
s2.erase(s2.find(Pair(a, b)));
}
bool okay = true;
if (s1.size() < 2) okay = false;
else if ((*s2.begin()).b >= (*(--s1.end())).a) okay = false;
puts(okay ? "YES" : "NO");
}
return 0;
}
E. Look Back
Problem
Sol&Code
取 \(log\) 后避免了爆炸的问题 \(·2\) 变为 \(+1\)。
#include <bits/stdc++.h>
#define N 100001
#define eps 1e-10
typedef long long ll;
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
double b[N];
int T, n, a[N];
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for (int i = 1; i <= n; ++i) b[i] = std::log(a[i]) / std::log(2.0);
long long ans = 0;
for (int i = 2; i <= n; ++i) {
if (b[i - 1] - b[i] >= eps) {
double cha = b[i - 1] - b[i];
int ad = cha;
if (cha - ad >= eps) ans += ad + 1, b[i] += ad + 1;
else ans += ad, b[i] += ad;
}
}
printf("%lld\n", ans);
}
return 0;
}
F. You Are So Beautiful
Problem
Sol&Code
对于原文中的一串 \(s_l s_{l + 1} s_{l + 2} \dots s_r\) 只出现一次即保证 \(l\) 前没有出现过 \(s_l\),\(r\) 后没有出现过 \(s_r\)。若其中任意一个出现过则与 \(s_l s_{l + 1} s_{l + 2} \dots s_r\) 相同的子序列不唯一,没有出现过则左端点与右端点固定了。题目转化为了维护第一次出现的字符的个数。
#include <bits/stdc++.h>
#define N 100001
#define lowbit(x) (x & -x)
typedef long long ll;
int T, n, a[N], bit[N];
void add(int x) {
while (x <= n) {
++bit[x];
x += lowbit(x);
}
}
ll ask(int x, ll res = 0) {
while (x > 0) {
res += bit[x];
x -= lowbit(x);
}
return res;
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) bit[i] = 0;
std::map<int, int> mp;
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for (int i = n; i >= 1; --i) {
++mp[a[i]];
if (mp[a[i]] == 1) add(n - i + 1);
}
std::map<int, int> mp2;
ll ans = 0;
for (int i = 1; i <= n; ++i) {
++mp2[a[i]];
if (mp2[a[i]] == 1) ans += ask(n - i + 1);
}
printf("%lld\n", ans);
}
return 0;
}
G1. Dances (Easy version)
Problem
Sol&Code
贪心的用双指针从小到大匹配 \(a\) 中元素与 \(b\) 中比该元素稍大的元素。
#include <bits/stdc++.h>
#define N 100001
int T, n, m, a[N], b[N];
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d %d", &n, &m);
a[1] = m;
for (int i = 2; i <= n; ++i) scanf("%d", &a[i]);
for (int i = 1; i <= n; ++i) scanf("%d", &b[i]);
std::sort(a + 1, a + n + 1);
std::sort(b + 1, b + n + 1);
int l = 1, r = 1, ans = 0;
while (l <= n && r <= n) {
while (l <= n && r <= n && b[r] > a[l]) ++l, ++r, ++ans;
++r;
}
printf("%d\n", n - ans);
}
return 0;
}
G2. Dances (Hard Version)
Problem
Sol&Code
一个数在不断变大的过程中最多使答案变大 \(1\) 一次。即该数由匹配到不匹配。
二分找什么时候变大即可。
#include <bits/stdc++.h>
#define N 100001
int T, n, m, k, a[N], b[N], c[N];
bool check(int x, int res = 0) {
c[1] = x;
for (int i = 2; i <= n; ++i) c[i] = a[i];
std::sort(c + 1, c + n + 1);
int p1 = 1, p2 = 1;
while (p1 <= n && p2 <= n) {
while (p1 <= n && p2 <= n && c[p1] < b[p2]) ++p1, ++p2, ++res;
++p2;
}
return res < k;
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d %d", &n, &m); a[1] = 1;
for (int i = 2; i <= n; ++i) scanf("%d", &a[i]);
for (int i = 1; i <= n; ++i) scanf("%d", &b[i]);
std::sort(a + 1, a + n + 1);
std::sort(b + 1, b + n + 1);
int p1 = 1, p2 = 1; k = 0;
while (p1 <= n && p2 <= n) {
while (p1 <= n && p2 <= n && a[p1] < b[p2]) ++p1, ++p2, ++k;
++p2;
}
int l = 1, r = m;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) r = mid - 1;
else l = mid + 1;
}
printf("%lld\n", 1ll * (n - k) * (l - 1) + 1ll * (n - k + 1) * (m - l + 1));
}
return 0;
}
After
赛时 \(E\) 精度出了问题。精度鲨我,害怕,救救。
还是做的太慢。
\(G2\) 好像有不用二分的做法。