T1:Similar String

模拟

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

char nomalize(char a) {
    if (a == '1') return 'l';
    if (a == '0') return 'o';
    return a;
}
string nomalize(string s) {
    rep(i, s.size()) s[i] = nomalize(s[i]);
    return s;
}

int main() {
    int n;
    cin >> n;
    string s, t;
    cin >> s >> t;
    
    s = nomalize(s);
    t = nomalize(t);
    
    if (s == t) puts("Yes");
    else puts("No");
    
    return 0;
}

T2:Discord

模拟

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

int main() {
    int n, m;
    cin >> n >> m;
    
    vector a(m, vector<int>(n));
    rep(i, m)rep(j, n) cin >> a[i][j];
    rep(i, m)rep(j, n) a[i][j]--;
    
    vector g(n, vector<bool>(n+1));
    rep(i, m) {
        rep(j, n-1) {
            g[a[i][j]][a[i][j+1]] = true;
        }
    }
    
    int ans = 0;
    rep(x, n)rep(y, x) {
        if (g[x][y] or g[y][x]) continue;
        ans++;
    }
    
    cout << ans << '\n';
    
    return 0;
}

T3:Dash

可以用 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, h, k;
    cin >> n >> m >> h >> k;
    string s;
    cin >> s;
    
    set<P> ps;
    rep(i, m) {
        int x, y;
        cin >> x >> y;
        ps.emplace(x, y);
    }
    
    int x = 0, y = 0;
    rep(i, n) {
        if (s[i] == 'R') x++;
        if (s[i] == 'L') x--;
        if (s[i] == 'U') y++;
        if (s[i] == 'D') y--;
        h--;
        if (h < 0) {
            puts("No");
            return 0;
        }
        if (ps.count(P(x, y))) {
            if (h < k) {
                h = k;
                ps.erase(P(x, y));
            }
        }
    }
    
    puts("Yes");
    
    return 0;
}

T4:Shift vs. CapsLock

dp[i][c] 表示输入 \(S\) 的前 \(i\) 个字符,且当前 CapsLock 的状态为 c ? ON : OFF 时所需最少用时

代码实现
// 1. 记忆化搜索
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

ll dp[300005][2];
bool memo[300005][2];

int main() {
    int x, y, z;
    cin >> x >> y >> z;
    string s;
    cin >> s;
    
    auto f = [&](auto f, int i, int c) -> ll {
        if (i == s.size()) return 0; 
        if (memo[i][c]) return dp[i][c];
        ll res = 1e18;
        int a = s[i] == 'A' ? 1 : 0;
        int cost1 = (a == c) ? x : y;
        int cost2 = z + ((a == c) ? y : x);
        res = cost1 + f(f, i+1, c);
        res = min(res, cost2 + f(f, i+1, c^1));
        memo[i][c] = true;
        return dp[i][c] = res;
    };
    
    cout << f(f, 0, 0) << '\n';
    
    return 0;
}

// 2. dp
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

inline void chmin(ll& x, ll y) { if (x > y) x = y; }

int main() {
    int x, y, z;
    cin >> x >> y >> z;
    string s;
    cin >> s;
    int n = s.size();
    
    const ll INF = 1e18;
    vector dp(n+1, vector<ll>(2, INF));
    dp[0][0] = 0;
    rep(i, n)rep(c, 2) {
        int a = s[i] == 'A';
        rep (nc, 2) {
            ll cost = (a == nc) ? x : y;
            if (c != nc) cost += z;
            chmin(dp[i+1][nc], dp[i][c] + cost); 
        }
    }
    
    cout << min(dp[n][0], dp[n][1]) << '\n';
    
    return 0;
}

T5:A Gift From the Stars

可以考虑从其中一个叶节点出发进行 \(\operatorname{dfs}\),若当前点的深度 \(\equiv 1 \pmod 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;
    
    vector<vector<int>> to(n);
    rep(i, n-1) {
        int a, b;
        cin >> a >> b;
        --a; --b;
        to[a].push_back(b);
        to[b].push_back(a);
    }
    
    int leaf = -1;
    rep(i, n) if (to[i].size() == 1) leaf = i;
    
    vector<int> ans;
    auto dfs = [&](auto f, int v, int p=-1, int d=0) -> void {
        if (d%3 == 1) ans.push_back(to[v].size());
        for (int u : to[v]) if (u != p) {
            f(f, u, v, d+1);
        }
    };
    dfs(dfs, leaf);
    
    sort(ans.begin(), ans.end());
    
    for (int a : ans) cout << a << ' ';
    
    return 0;
}

T6:Damage over Time

可以从后往前考虑
如果能在 \(k\) 回合以内打到的话,咒文 \(i\) 的总伤害就是 \(\min(t_i, k) \cdot d_i\),所以使用能让这个值最大化的咒文就可以了!

可以将使用相同咒文的回合放在一起计算,从而加速这个过程。

T7:Bags Game

可以考虑区间 \(dp\)

dp[l][r] 表示两人从区间 \([l, r)\) 开始分别采用最优策略得到的 \(\max(X-Y)\)

然后用线段树来加速查询区间最小值即可

代码实现
#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;

inline void chmax(ll& a, ll b) { if (a < b) a = b; }

const ll INF = 1e18;
ll op(ll a, ll b) { return min(a, b); }
ll e() { return INF; }

int main() {
    int n, a, b, c, d;
    cin >> n >> a >> b >> c >> d;
    
    vector<int> x(n);
    rep(i, n) cin >> x[i];
    
    vector<ll> s(n+1);
    rep(i, n) s[i+1] = s[i]+x[i];
    auto sum = [&](int l, int r) { return s[r]-s[l]; };
    
    vector dp(n+1, vector<ll>(n+1, -INF));
    rep(i, n+1) dp[i][i] = 0;
    
    using seg = segtree<ll, op, e>;
    vector<seg> t(n+1, seg(n));
    
    for (int w = 1; w <= n; ++w) {
        rep(l, n) {
            int r = l+w;
            if (r > n) break;
            ll now = -INF;
            chmax(now, x[l]-dp[l+1][r]);
            chmax(now, x[r-1]-dp[l][r-1]);
            auto upd = [&](int a, int b) {
                if (w <= b) {
                    chmax(now, sum(l, r)-a);
                }
                else {
                    ll val = t[w-b].prod(l, l+b+1);
                    chmax(now, sum(l, r)-val-a);
                }
            };
            upd(a, b); upd(c, d);
            dp[l][r] = now;
            t[w].set(l, now+sum(l, r));
        }
    }
    
    cout << dp[0][n] << '\n';
    
    return 0;
}

T8:Constrained Tree Degree

可以考虑 prufer序列

结论:

顶点 \(i\)\(d_i\) 的生成树有 \(\frac{(n-2)!}{\prod (d_i-1)!}\)

我们需要求的是 \(\sum\limits_d \frac{(n-2)!}{\prod\limits_{i} (d_i-1)!}\)
可以适当做一下变形,\((n-2)! \cdot \sum\limits_d \prod\limits_i\frac{1}{(d_i-1)!}\)

其中,\(\sum\limits_d \prod\limits_i\frac{1}{(d_i-1)!}\) 这一部分可以转成指数型生成函数求解

\(F = \sum\limits_{s \in S} \frac{1}{(s-1)!}x^s\)

那么,最后的答案就是 \((n-2)! \cdot [x^{2n-2}]F^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;

// combination mod prime
struct modinv {
  int n; vector<mint> d;
  modinv(): n(2), d({0,1}) {}
  mint operator()(int i) {
    while (n <= i) d.push_back(-d[mint::mod()%n]*(mint::mod()/n)), ++n;
    return d[i];
  }
  mint operator[](int i) const { return d[i];}
} invs;
struct modfact {
  int n; vector<mint> d;
  modfact(): n(2), d({1,1}) {}
  mint operator()(int i) {
    while (n <= i) d.push_back(d.back()*n), ++n;
    return d[i];
  }
  mint operator[](int i) const { return d[i];}
} facts;
struct modfactinv {
  int n; vector<mint> d;
  modfactinv(): n(2), d({1,1}) {}
  mint operator()(int i) {
    while (n <= i) d.push_back(d.back()*invs(n)), ++n;
    return d[i];
  }
  mint operator[](int i) const { return d[i];}
} ifacts;
mint comb(int n, int k) {
  if (n < k || k < 0) return 0;
  return facts(n)*ifacts(k)*ifacts(n-k);
}

// Formal Power Series
using vm = vector<mint>;
struct fps : vm {
#define d (*this)
#define s int(vm::size())
  template<class...Args> fps(Args...args): vm(args...) {}
  fps(initializer_list<mint> a): vm(a.begin(),a.end()) {}
  void rsz(int n) { if (s < n) resize(n);}
  fps& low_(int n) { resize(n); return d;}
  fps low(int n) const { return fps(d).low_(n);}
  mint& operator[](int i) { rsz(i+1); return vm::operator[](i);}
  mint operator[](int i) const { return i<s ? vm::operator[](i) : 0;}
  mint operator()(mint x) const {
    mint r;
    for (int i = s-1; i >= 0; --i) r = r*x+d[i];
    return r;
  }
  fps operator-() const { fps r(d); rep(i,s) r[i] = -r[i]; return r;}
  fps& operator+=(const fps& a) { rsz(a.size()); rep(i,a.size()) d[i] += a[i]; return d;}
  fps& operator-=(const fps& a) { rsz(a.size()); rep(i,a.size()) d[i] -= a[i]; return d;}
  fps& operator*=(const fps& a) { return d = convolution(d, a);}
  fps& operator*=(mint a) { rep(i,s) d[i] *= a; return d;}
  fps& operator/=(mint a) { rep(i,s) d[i] /= a; return d;}
  fps operator+(const fps& a) const { return fps(d) += a;}
  fps operator-(const fps& a) const { return fps(d) -= a;}
  fps operator*(const fps& a) const { return fps(d) *= a;}
  fps operator*(mint a) const { return fps(d) *= a;}
  fps operator/(mint a) const { return fps(d) /= a;}
  fps operator~() const {
    fps r({d[0].inv()});
    for (int i = 1; i < s; i <<= 1) r = r*mint(2) - (r*r*low(i<<1)).low(i<<1);
    return r.low_(s);
  }
  fps& operator/=(const fps& a) { int w = s; d *= ~a; return d.low_(w);}
  fps operator/(const fps& a) const { return fps(d) /= a;}
  fps integ() const {
    fps r;
    rep(i,s) r[i+1] = d[i]/(i+1);
    return r;
  }
  fps pow(int t) {
    if (t == 1) return *this;
    fps r = pow(t>>1);
    (r *= r).low_(s);
    if (t&1) (r *= *this).low_(s);
    return r;
  }
#undef s
#undef d
};
ostream& operator<<(ostream&o,const fps&a) {
  rep(i,a.size()) o<<(i?" ":"")<<a[i].val();
  return o;
}

int main() {
    cin.tie(nullptr) -> sync_with_stdio(false);
    
    int n, k;
    cin >> n >> k;
    
    int m = n*2-2;
    fps f(m+1);
    rep(i, k) {
        int s;
        cin >> s;
        f[s] = ifacts(s-1);
    }
    f.pow(n);
    
    mint ans = f.pow(n)[m]*facts(n-2);
    cout << ans.val() << '\n';
    
    return 0;
}