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