A. Poisonous Oyster

简单分讨

代码实现
#include <bits/stdc++.h>
using namespace std;
int main() {
string s1, s2;
cin >> s1 >> s2;
int ans = 1;
if (s1 == "fine") ans += 2;
if (s2 == "fine") ans += 1;
cout << ans << '\n';
return 0;
}

B. A..B..C

模拟

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
string s;
cin >> s;
int n = s.size();
int ans = 0;
rep(i, n)rep(j, n)rep(k, n) {
if (i >= j or j >= k) continue;
if (j-i != k-j) continue;
if (s[i] != 'A') continue;
if (s[j] != 'B') continue;
if (s[k] != 'C') continue;
ans++;
}
cout << ans << '\n';
return 0;
}

C. Make it Simple

仅考虑 a<b 的边,可以用 std::set 来维护

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
int main() {
int n, m;
cin >> n >> m;
set<P> edges;
rep(i, m) {
int a, b;
cin >> a >> b;
--a; --b;
if (a == b) continue;
if (a > b) swap(a, b);
if (edges.count(P(a, b))) continue;
edges.emplace(a, b);
}
int ans = m-edges.size();
cout << ans << '\n';
return 0;
}

D. Swap to Gather

考虑每个 1 左边 0 的个数构成的序列,不妨记为 a
问题就变成了可以对 a 通过 +1-1 使得 a 序列每个数相等的最小操作次数
结论是当目标值取到 a 的中位数时操作次数最少

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n;
string s;
cin >> n >> s;
vector<int> p;
rep(i, n) if (s[i] == '1') p.push_back(i);
int k = p.size();
rep(i, k) p[i] -= i;
int med = p[k/2];
ll ans = 0;
rep(i, k) ans += abs(med-p[i]);
cout << ans << '\n';
return 0;
}

E. GCD of Subset

调和级数
统计每种数的倍数的个数

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, k;
cin >> n >> k;
vector<int> a(n);
rep(i, n) cin >> a[i];
const int m = 1000000;
vector<int> num(m+1);
for (int na : a) num[na]++;
vector<int> c(m+1);
for (int j = 1; j <= m; ++j) {
for (int i = j; i <= m; i += j) c[j] += num[i];
}
vector<int> best(m+1);
for (int g = 1; g <= m; ++g) {
if (c[g] < k) continue;
for (int i = g; i <= m; i += g) best[i] = g;
}
rep(i, n) {
int ans = best[a[i]];
cout << ans << '\n';
}
return 0;
}

F. Prefix LIS Query

离线(当然也可以在线)
将每个询问按 R 值做升序排序
然后遍历每个 R,求出到当前为止的 lis
dp[i] 表示长度为 ilis 的最后一个数的最小值
这个序列可以用二分来求
对于 R 对应的每个询问的答案,可以对上面的 dp 序列二分

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
int main() {
int n, q;
cin >> n >> q;
vector<int> a(n);
rep(i, n) cin >> a[i];
vector<vector<P>> qs(n);
rep(i, q) {
int r, x;
cin >> r >> x;
--r;
qs[r].emplace_back(i, x);
}
const int INF = 1001001001;
vector<int> dp(n, INF);
vector<int> ans(q);
rep(i, n) {
int j = lower_bound(dp.begin(), dp.end(), a[i]) - dp.begin();
dp[j] = a[i];
for (auto [qi, x] : qs[i]) {
ans[qi] = lower_bound(dp.begin(), dp.end(), x+1) - dp.begin();
}
}
rep(i, q) cout << ans[i] << '\n';
return 0;
}