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;
}