T1:Arithmetic Progression
模拟
代码实现
a, b, d = map(int, input().split())
for i in range(a, b+1, d):
print(i, end=' ')
T2:Append
模拟
代码实现
q = int(input())
a = []
for qi in range(q):
type, x = map(int, input().split())
if type == 1:
a.append(x)
else:
print(a[-x])
T3:Divide and Divide
记忆化搜索
代码实现
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ll n;
cin >> n;
unordered_map<ll, ll> memo;
auto f = [&](auto& f, ll x) -> ll {
if (x == 1) return 0;
if (memo.count(x)) return memo[x];
ll res = f(f, x/2) + f(f, x-x/2) + x;
return memo[x] = res;
};
cout << f(f, n) << '\n';
return 0;
}
T4:Super Takahashi Bros.
注意到由于图可能不是dag,所以不能dp
考虑对点 \(i\) 到点 \(i+1\) 连一条有向边且边权为 \(A_i\),再对点 \(i\) 到点 \(X_i\) 连一条有向边且边权为 \(B_i\),这样就得到了一张带权有向图,所以直接跑一遍最短路就能得到答案
代码实现
#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, x;
cin >> a >> b >> x;
--x;
g[i].emplace_back(i+1, a);
g[i].emplace_back(x, b);
}
const ll INF = 1e18;
vector<ll> dist(n, INF);
using P = pair<ll, int>;
priority_queue<P, vector<P>, greater<P>> q;
dist[0] = 0;
q.emplace(0, 0);
while (q.size()) {
auto [d, v] = q.top(); q.pop();
if (dist[v] != d) continue;
for (auto e : g[v]) {
ll nd = d+e.cost;
if (nd >= dist[e.to]) continue;
dist[e.to] = nd;
q.emplace(nd, e.to);
}
}
cout << dist[n-1] << '\n';
return 0;
}
T5:Mancala 2
- 区间更新
- 单点求值
可以用线段树或树状数组来做
树状数组的话,可以用差分来实现区间更新,用前缀和来实现单点求值
代码实现
#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 ll = long long;
int main() {
int n, m;
cin >> n >> m;
fenwick_tree<ll> d(n+1);
auto add = [&](int l, int r, ll x) {
d.add(l, x);
d.add(r, -x);
};
rep(i, n) {
int a;
cin >> a;
add(i, i+1, a);
}
rep(i, m) {
int b;
cin >> b;
ll x = d.sum(0, b+1);
add(b, b+1, -x);
ll c = x/n; x %= n;
add(0, n, c);
b++;
if (b+x < n) {
add(b, b+x, 1);
}
else {
add(b, n, 1);
add(0, b+x-n, 1);
}
}
rep(i, n) {
ll ans = d.sum(0, i+1);
cout << ans << ' ';
}
return 0;
}
T6:S = 1
由向量积的知识可知,三角形的面积等于 \(\frac{|BX-AY|}{2}\),得到 \(|BX-AY| = 2\),于是就转成了扩欧的板题
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
// ai+bj=g
ll extgcd(ll a, ll b, ll& i, ll& j) {
if (b == 0) { i = 1; j = 0; return a; }
ll p = a/b, g = extgcd(b, a-b*p, j, i);
j -= p*i;
return g;
}
int main() {
ll x, y;
cin >> x >> y;
ll a, b;
ll g = extgcd(x, y, b, a);
a = -a;
if (2%g) {
puts("-1");
return 0;
}
a *= 2/g; b *= 2/g;
cout << a << ' ' << b << '\n';
return 0;
}
T7:Leaf Color
考虑枚举度数为 \(1\) 的点的颜色,然后跑树形dp即可
记 dp[v]
表示在以 \(v\) 为根的子树中合法的诱导子图的个数
然而时间复杂度是 \(O(n^2)\)
可以通过仅在虚树上dp将时间复杂度降到 \(O(n\log n)\)
代码实现
#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 mint = modint998244353;
// Lowest Common Ancestor by binary lifting
template<typename T=int> // T: type of cost
struct lca {
int n, root, l;
vector<vector<int>> to;
vector<vector<T>> co;
vector<int> dep;
vector<T> costs;
vector<vector<int>> par;
lca(int n):n(n),to(n),co(n),dep(n),costs(n) {
l = 0;
while ((1<<l) < n) ++l;
par = vector<vector<int>>(n+1,vector<int>(l,n));
}
void addEdge(int a, int b, T c=0) {
to[a].push_back(b); co[a].push_back(c);
to[b].push_back(a); co[b].push_back(c);
}
void dfs(int v, int d=0, T c=0, int p=-1) {
if (p != -1) par[v][0] = p;
dep[v] = d;
costs[v] = c;
for (int i = 0; i < to[v].size(); ++i) {
int u = to[v][i];
if (u == p) continue;
dfs(u, d+1, c+co[v][i], v);
}
}
void init(int _root=0) {
root = _root;
dfs(root);
for (int i = 0; i < l-1; ++i) {
for (int v = 0; v < n; ++v) {
par[v][i+1] = par[par[v][i]][i];
}
}
}
// LCA
int up(int v, int k) {
for (int i = l-1; i >= 0; --i) {
int len = 1<<i;
if (k >= len) k -= len, v = par[v][i];
}
return v;
}
int operator()(int a, int b) {
if (dep[a] > dep[b]) swap(a,b);
b = up(b, dep[b]-dep[a]);
if (a == b) return a;
for (int i = l-1; i >= 0; --i) {
int na = par[a][i], nb = par[b][i];
if (na != nb) a = na, b = nb;
}
return par[a][0];
}
int length(int a, int b) {
int c = (*this)(a,b);
return dep[a]+dep[b]-dep[c]*2;
}
T dist(int a, int b) {
int c = (*this)(a,b);
return costs[a]+costs[b]-costs[c]*2;
}
};
int main() {
int n;
cin >> n;
vector<vector<int>> cvs(n);
vector<int> col(n);
rep(i, n) {
int a;
cin >> a;
a--;
col[i] = a;
cvs[a].push_back(i);
}
vector<vector<int>> to(n);
lca g(n);
rep(i, n-1) {
int a, b;
cin >> a >> b;
--a; --b;
g.addEdge(a, b);
to[a].push_back(b);
to[b].push_back(a);
}
g.init();
vector<int> in(n), out(n);
{
int k = 0;
auto dfs = [&](auto& f, int v, int p=-1) -> void {
in[v] = k++;
for (int u : to[v]) {
if (u == p) continue;
f(f, u, v);
}
out[v] = k;
};
dfs(dfs, 0);
}
mint ans;
vector<vector<int>> to2(n);
rep(ci, n) {
vector<int>& vs = cvs[ci];
if (vs.size() == 0) continue;
sort(vs.begin(), vs.end(), [&](int a, int b) { return in[a] < in[b]; });
int m = vs.size();
rep(i, m-1) {
vs.push_back(g(vs[i], vs[i+1]));
}
sort(vs.begin(), vs.end(), [&](int a, int b) { return in[a] < in[b]; });
vs.erase(unique(vs.begin(), vs.end()), vs.end());
{
vector<int> st;
for (int v : vs) {
while (st.size()) {
int p = st.back();
if (in[p] < in[v] and in[v] < out[p]) break;
st.pop_back();
}
if (st.size()) to2[st.back()].push_back(v);
st.push_back(v);
}
}
auto dfs = [&](auto& f, int v) -> mint {
mint res;
for (int u : to2[v]) {
mint x = f(f, u);
if (col[v] != ci) ans += res*x;
res += (res+1)*x;
}
if (col[v] == ci) {
res += 1;
ans += res;
}
return res;
};
dfs(dfs, vs[0]);
for (int v : vs) to2[v] = vector<int>();
}
cout << ans.val() << '\n';
return 0;
}