A. 369

AB 之间可以插一个数构成等差数列当且仅当 A+B 是偶数

特例:A=B,此时答案是 1

代码实现
a, b = map(int, input().split())
if a == b: print(1)
elif (a+b)%2 == 0: print(3)
else: print(2)

B. Piano 3

把左手和右手分别放在对应的最左侧然后按顺序模拟即可

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
cin >> n;
int ans = 0;
int l = -1, r = -1;
rep(i, n) {
int a; char s;
cin >> a >> s;
if (s == 'L') {
if (l != -1) ans += abs(l-a);
l = a;
}
else {
if (r != -1) ans += abs(r-a);
r = a;
}
}
cout << ans << '\n';
return 0;
}

C. Count Arithmetic Subarrays

双指针

代码实现
#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;
cin >> n;
vector<int> a(n);
rep(i, n) cin >> a[i];
ll ans = 0;
int r = 0;
rep(l, n) {
while (r < n) {
if (r > l+1 and a[r]-a[r-1] != a[r-1]-a[r-2]) break;
++r;
}
ans += r-l;
}
cout << ans << '\n';
return 0;
}

D. Bonus EXP

简单dp
dp[i][j] 表示到第 i 只怪兽为止已经打的怪兽的个数 % 2=j 时能获得的最大经验值

时间复杂度为 O(N)

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
inline void chmax(ll& x, ll y) { if (x < y) x = y; }
int main() {
int n;
cin >> n;
vector<int> a(n);
rep(i, n) cin >> a[i];
const ll INF = 1e18;
vector dp(n+1, vector<ll>(2, -INF));
dp[0][0] = 0;
rep(i, n) {
int ni = i+1;
rep(j, 2) {
{ // o
int nj = j^1;
int X = j%2 ? a[i]*2 : a[i];
chmax(dp[ni][nj], dp[i][j]+X);
}
{ // x
int nj = j;
chmax(dp[ni][nj], dp[i][j]);
}
}
}
ll ans = max(dp[n][0], dp[n][1]);
cout << ans << '\n';
return 0;
}

E. Sightseeing Tour

注意到 k5 这个条件,这道题就做完了
只需枚举这 k 条边不同的顺序和每条边的方向
n400 暗示我们可以跑 floyd
那么复杂度就是 O(n3+qk!2k)

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using Edge = tuple<int, int, int>;
inline void chmin(ll& a, ll b) { if (a > b) a = b; }
int main() {
int n, m;
cin >> n >> m;
vector<Edge> es;
const ll INF = 1e18;
vector dist(n, vector<ll>(n, INF));
rep(i, n) dist[i][i] = 0;
rep(i, m) {
int a, b, c;
cin >> a >> b >> c;
--a; --b;
es.emplace_back(a, b, c);
chmin(dist[a][b], c);
chmin(dist[b][a], c);
}
rep(k, n)rep(i, n)rep(j, n) chmin(dist[i][j], dist[i][k]+dist[k][j]);
int q;
cin >> q;
rep(qi, q) {
int k;
cin >> k;
vector<int> ei(k);
rep(i, k) cin >> ei[i], ei[i]--;
ll ans = INF;
do {
rep(s, 1<<k) {
ll now = 0;
int v = 0;
rep(i, k) {
auto [a, b, c] = es[ei[i]];
if (s>>i&1) swap(a, b);
now += dist[v][a];
now += c;
v = b;
}
now += dist[v][n-1];
chmin(ans, now);
}
} while (next_permutation(ei.begin(), ei.end()));
cout << ans << '\n';
}
return 0;
}

F. Gather Coins

这题本质上就是求二维上升子序列
可以用扫描线和线段树加速

代码实现
#include <bits/stdc++.h>
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
#endif
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
P op(P a, P b) { return max(a, b); }
P e() { return P(0, -1); }
int main() {
int h, w, n;
cin >> h >> w >> n;
vector<P> coins;
rep(i, n) {
int r, c;
cin >> r >> c;
coins.emplace_back(r, c);
}
ranges::sort(coins);
const int MX = 200005;
segtree<P, op, e> t(MX);
vector<int> pre(n);
rep(i, n) {
int y = coins[i].second;
auto [lis, idx] = t.prod(0, y+1);
pre[i] = idx;
t.set(y, P(lis+1, i));
}
string ans;
int r = h, c = w;
auto mv = [&](P p) {
auto [nr, nc] = p;
while (r > nr) r--, ans += 'D';
while (c > nc) c--, ans += 'R';
};
auto [lis, i] = t.all_prod();
while (i != -1) {
mv(coins[i]);
i = pre[i];
}
mv(P(1, 1));
ranges::reverse(ans);
cout << lis << '\n';
cout << ans << '\n';
return 0;
}

G. As far as possible

可以发现答案就是由点 1 和指定的 k 个点构成的树形图上每条边的边权 ×2 的总和
青木为了让答案最大,应该尽可能地选距离点 1 更远的叶子节点,等选完叶子节点以后,剩下的答案保持不变
那么怎么来求答案呢?

  • 树形dp+multiset做dsu on tree

我们可以对树上每个点维护一个可重集,对于 vu 这条边,边权为 w,取出点 u 的可重集中的最大值 x,同时将这个最大值在点 u 的可重集中删去,然后将 x+w 加入点 v 的可重集中

具体分析可以参考 tiger2005题解

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
struct Edge {
int to, cost;
Edge() {}
Edge(int to, int cost): to(to), cost(cost) {}
};
int main() {
int n;
cin >> n;
vector<vector<Edge>> g(n);
rep(i, n-1) {
int a, b, c;
cin >> a >> b >> c;
--a; --b;
g[a].emplace_back(b, c);
g[b].emplace_back(a, c);
}
auto dfs = [&](auto& dfs, int v, int p=-1) -> multiset<ll> {
multiset<ll> f;
for (auto [u, w] : g[v]) {
if (u == p) continue;
auto nf = dfs(dfs, u, v);
ll x = *nf.rbegin(); nf.erase(prev(nf.end()));
nf.insert(x+w);
if (f.size() < nf.size()) swap(f, nf);
f.merge(nf);
}
f.insert(0);
return f;
};
auto f = dfs(dfs, 0);
vector<ll> as;
for (ll x : f) as.push_back(x);
ranges::reverse(as);
ll ans = 0;
for (ll a : as) {
cerr << a << '\n';
ans += a*2;
cout << ans << '\n';
}
return 0;
}