题号 | 标题 | 团队的状态 |
---|---|---|
A | A Math Challenge | 通过 |
B | Best Subgraph | 未通过 |
C | Cells | 通过 |
D | Divide-and-conquer on Tree | 未通过 |
E | Eyjafjalla | 通过 |
F | Financial Order Execution | 未通过 |
G | Glass Balls | 通过 |
H | Happy Number | 通过 |
I | Incentive Model | 通过 |
J | Jam | 通过 |
A Math Challenge
LOJ138 + 自然数幂和。
// Author: HolyK
// Created: Sun Aug 15 21:59:21 2021
#include <bits/stdc++.h>
template <class T, class U>
inline bool smin(T &x, const U &y) {
return y < x ? x = y, 1 : 0;
}
template <class T, class U>
inline bool smax(T &x, const U &y) {
return x < y ? x = y, 1 : 0;
}
using LL = long long;
using PII = std::pair<int, int>;
constexpr int P(998244353);
inline void inc(int &x, int y) {
+= y;
x if (x >= P) x -= P;
}
inline void dec(int &x, int y) {
-= y;
x if (x < 0) x += P;
}
inline int mod(LL x) {
return x % P;
}
int fpow(int x, int k = P - 2) {
int r = 1;
for (; k; k >>= 1, x = 1LL * x * x % P) {
if (k & 1) r = 1LL * r * x % P;
}
return r;
}
struct Z {
int x;
(int v = 0) : x(v < 0 ? v + P : v >= P ? v - P : v) {}
Z() const {
Z invassert(x);
return Z(fpow(x));
}
(int k) const {
Z powreturn Z(fpow(x, k));
}
&operator+=(const Z &r) {
Z (x, r.x);
increturn *this;
}
&operator-=(const Z &r) {
Z (x, r.x);
decreturn *this;
}
&operator*=(const Z &r) {
Z = 1LL * x * r.x % P;
x return *this;
}
&operator/=(const Z &r) {
Z = 1LL * x * fpow(r.x) % P;
x return *this;
}
operator+(const Z &r) const {
Z return Z(*this) += r;
}
operator-(const Z &r) const {
Z return Z(*this) -= r;
}
operator*(const Z &r) const {
Z return Z(*this) *= r;
}
operator/(const Z &r) const {
Z return Z(*this) /= r;
}
operator-() const {
Z return Z(P - x);
}
operator int() const {
return x;
}
};
[52][52], inv[52];
Z binstruct Info {
, x, f[52][52];
Z i() : i(0), x(0) {
Info(f, 0, sizeof f);
memset}
};
int n, m;
operator*(Info a, Info b) {
Info ;
Info c.i = a.i + b.i;
c.x = a.x + b.x;
cfor (int i = 0; i <= n; i++) {
for (int j = 0; j <= m; j++) {
.f[i][j] = a.f[i][j];
c}
}
= 1, v, bu;
Z u for (int j = 0; j <= n; j++, u *= a.i) {
for (int p = j; p <= n; p++) {
= bin[p][j] * u, v = 1;
bu for (int k = 0; k <= m; k++, v *= a.x) {
for (int q = k; q <= m; q++) {
.f[p][q] += bu * bin[q][k] * v * b.f[p - j][q - k];
c}
}
}
}
return c;
}
(Info x, LL k) {
Info fpow;
Info rfor (; k; k >>= 1, x = x * x) {
if (k & 1) r = r * x;
}
return r;
}
(LL p, LL i, LL r, LL q) {
LL divreturn (p * i + r) / q;
}
(LL p, LL r, LL q, LL n, const Info &x, const Info &y) {
Info calif (n < 0) return Info();
if (r >= q) {
return fpow(y, r / q) * cal(p, r % q, q, n, x, y);
}
if (p >= q) {
return x * cal(p % q, p % q + r, q, n - 1, fpow(y, p / q) * x, y);
}
if (p == 0) {
return fpow(x, n + 1);
}
= div(p, n, r, q);
LL m return cal(q, q - r + p - 1, p, m - 1, y, x) * fpow(x, n + 1 - (!m ? 0 : div(q, m, p - r - 1, p)));
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
for (int i = 0; i <= 51; i++) {
[i][0] = 1;
binfor (int j = 1; j <= i; j++) {
[i][j] = bin[i - 1][j] + bin[i - 1][j - 1];
bin}
}
int a, b, c, p, q, n;
std::cin >> a >> b >> c >> p >> q >> n;
++;
q::n = p, ::m = q;
, y;
Info x.i = x.f[0][0] = y.x = 1;
xauto pw = cal(a, b, c, n, x, y);
{
std::vector<std::vector<Z>> a(q, std::vector<Z>(q + 1));
= 0;
Z sum for (int i = 0; i < q; i++) {
for (int j = 0; j < q; j++) {
[i][j] = fpow(i + 1, j + 1);
a}
[i].back() = sum += fpow(i + 1, q - 1);
a}
for (int i = 0, j; i < q; i++) {
for (j = i; j < q; j++) {
if (!a[j][i]) continue;
std::swap(a[i], a[j]);
break;
}
assert(a[i][i]);
= a[i][i].inv();
Z inv for (int k = 0; k <= q; k++) a[i][k] *= inv;
for (j = 0; j < q; j++) {
if (j == i || !a[j][i]) continue;
for (int k = q; k >= i; k--) {
[j][k] -= a[j][i] * a[i][k];
a}
}
}
;
Z ansfor (int i = 0; i < q; i++) {
+= pw.f[p][i + 1] * a[i].back();
ans }
std::cout << ans << "\n";
}
return 0;
}
Best Subgraph
Cells
Divide-and-conquer on Tree
Eyjafjalla
Financial Order Execution
Glass Balls
Solution 1
很难直接计算 \(f(i)\) 。
考虑条件期望,设事件 \(C_i\) 表示点 \(i\) 合法,即最多有一个儿子可以放行,事件 \(N_i\) 表示 \(i\) 到根这条路上的点合法,事件 \(N\) 表示整棵树合法。
设 \(X_{i, s}\) 表示球 \(i\) 从 \(s\) 开始,不考虑碰撞答案清零,会经过多少条边,特别地,记 \(X_i = X_{i, i}\)。
可以发现,\(X_{i,s}\) 只和 \(i\) 到根的路径上的情况有关,和其他事件是独立的,所以有 \[ \begin{aligned} E(X|N) &= \sum_{}E(X_i|N)\\ &= \sum\sum x\frac{P(X_i = x,N)}{P(N)}\\ &= \sum\sum x\frac{P(X_i = x,N_{f_i}, N-N_{f_i})}{P(N_{f_i}, N-N_{f_i})}\\ &= \sum\sum x\frac{P(X_i = x,N_{f_i})}{P(N_{f_i})}\\ &= \sum E(X_i|N_{f_i}) \end{aligned} \] 设 \(Y_i\) 表示 \(i\) 的儿子中可以通过的是哪个(可以都没有,此时 \(Y=0\) )。
根据期望的线性性,有 \[ \begin{aligned} E(X_i | N_{f_i}) &= E((X_{i, f_i} + 1) | N_{f_i})\\ &= E(X_{i, f_i}|N_{f_i}) + P(Y_{f_i} = i | N_{f_i})\\ &= [E(X_{f_i}|N_{f_{f_i}}) + 1]P(Y_{f_i} = i | C_{f_i})\\ \end{aligned} \] 答案是 \(E(X, N) = E(X|N)P(N)\)。
// Author: HolyK
// Created: Sat Aug 14 21:08:18 2021
#include <bits/stdc++.h>
template <class T, class U>
inline bool smin(T &x, const U &y) {
return y < x ? x = y, 1 : 0;
}
template <class T, class U>
inline bool smax(T &x, const U &y) {
return x < y ? x = y, 1 : 0;
}
using LL = long long;
using PII = std::pair<int, int>;
constexpr int P(998244353);
inline void inc(int &x, int y) {
+= y;
x if (x >= P) x -= P;
}
inline void dec(int &x, int y) {
-= y;
x if (x < 0) x += P;
}
inline int mod(LL x) {
return x % P;
}
int fpow(int x, int k = P - 2) {
int r = 1;
for (; k; k >>= 1, x = 1LL * x * x % P) {
if (k & 1) r = 1LL * r * x % P;
}
return r;
}
struct Z {
int x;
(int v = 0) : x(v < 0 ? v + P : v >= P ? v - P : v) {}
Z() const {
Z invassert(x);
return Z(fpow(x));
}
(int k) const {
Z powreturn Z(fpow(x, k));
}
&operator+=(const Z &r) {
Z (x, r.x);
increturn *this;
}
&operator-=(const Z &r) {
Z (x, r.x);
decreturn *this;
}
&operator*=(const Z &r) {
Z = 1LL * x * r.x % P;
x return *this;
}
&operator/=(const Z &r) {
Z = 1LL * x * fpow(r.x) % P;
x return *this;
}
operator+(const Z &r) const {
Z return Z(*this) += r;
}
operator-(const Z &r) const {
Z return Z(*this) -= r;
}
operator*(const Z &r) const {
Z return Z(*this) *= r;
}
operator/(const Z &r) const {
Z return Z(*this) /= r;
}
operator-() const {
Z return Z(P - x);
}
operator int() const {
return x;
}
};
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
, np;
Z pstd::cin >> n >> p.x;
= Z(1) - p;
np std::vector<std::vector<int>> g(n);
for (int i = 1; i < n; i++) {
int x;
std::cin >> x;
--;
x[x].push_back(i);
g}
, prod = 1;
Z ansstd::function<void(int, Z)> dfs = [&](int x, Z d) {
+= d;
ans if (!g[x].size()) {
return;
}
= p.pow(g[x].size() - 1) * np;
Z k = k * Z(g[x].size()) + p.pow(g[x].size());
Z v *= v;
prod /= v;
k for (int y : g[x]) {
(y, (d + Z(1)) * k);
dfs}
};
(0, 0);
dfsstd::cout << ans * prod << "\n";
return 0;
}
Solution 2
将起点和终点交换,考虑计算每个点向下能走多少距离。
设 \(f(i)\) 表示在 \(i\) 的子树合法的情况下,\(i\) 向下走的距离,\(s(i)\) 表示在 \(i\) 的子树合法的情况下,\(i\) 子树的答案和,\(v(i)\) 表示 \(i\) 的子树合法的概率。
详细推导略。
// Author: HolyK
// Created: Sun Aug 15 10:11:38 2021
#include <bits/stdc++.h>
template <class T, class U>
inline bool smin(T &x, const U &y) {
return y < x ? x = y, 1 : 0;
}
template <class T, class U>
inline bool smax(T &x, const U &y) {
return x < y ? x = y, 1 : 0;
}
using LL = long long;
using PII = std::pair<int, int>;
constexpr int P(998244353);
inline void inc(int &x, int y) {
+= y;
x if (x >= P) x -= P;
}
inline void dec(int &x, int y) {
-= y;
x if (x < 0) x += P;
}
inline int mod(LL x) {
return x % P;
}
int fpow(int x, int k = P - 2) {
int r = 1;
for (; k; k >>= 1, x = 1LL * x * x % P) {
if (k & 1) r = 1LL * r * x % P;
}
return r;
}
struct Z {
int x;
(int v = 0) : x(v < 0 ? v + P : v >= P ? v - P : v) {}
Z() const {
Z invassert(x);
return Z(fpow(x));
}
(int k) const {
Z powreturn Z(fpow(x, k));
}
&operator+=(const Z &r) {
Z (x, r.x);
increturn *this;
}
&operator-=(const Z &r) {
Z (x, r.x);
decreturn *this;
}
&operator*=(const Z &r) {
Z = 1LL * x * r.x % P;
x return *this;
}
&operator/=(const Z &r) {
Z = 1LL * x * fpow(r.x) % P;
x return *this;
}
operator+(const Z &r) const {
Z return Z(*this) += r;
}
operator-(const Z &r) const {
Z return Z(*this) -= r;
}
operator*(const Z &r) const {
Z return Z(*this) *= r;
}
operator/(const Z &r) const {
Z return Z(*this) /= r;
}
operator-() const {
Z return Z(P - x);
}
operator int() const {
return x;
}
};
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
;
Z pstd::cin >> p.x;
= Z(1) - p;
Z np std::vector<std::vector<int>> g(n);
for (int i = 1, x; i < n; i++) {
std::cin >> x;
[x - 1].push_back(i);
g}
std::vector<Z> f(n), s(n), v(n);
std::function<void(int)> dfs = [&](int x) {
[x] = 1;
vif (!g[x].size()) {
return;
}
for (int y : g[x]) {
(y);
dfs[x] *= v[y];
v}
= p.pow(g[x].size() - 1) * np;
Z k = k * Z(g[x].size()) + p.pow(g[x].size());
Z c for (int y : g[x]) {
= v[x] / v[y];
Z py [x] += s[y] * py * c;
s[x] += (f[y] + v[y]) * py * k;
f}
[x] *= c;
v[x] += f[x];
s};
(0);
dfsstd::cout << s[0] << "\n";
return 0;
}
Happy Number
Incentive Model
Jam
最后修改于 2021-08-31