QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#116507 | #4885. Triangular Cactus Paths | hos_lyric | TL | 48ms | 98700kb | C++14 | 12.1kb | 2023-06-29 13:40:14 | 2023-06-29 13:40:16 |
Judging History
answer
#include <cassert>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
using Int = long long;
template <class T1, class T2> ostream &operator<<(ostream &os, const pair<T1, T2> &a) { return os << "(" << a.first << ", " << a.second << ")"; };
template <class T> ostream &operator<<(ostream &os, const vector<T> &as) { const int sz = as.size(); os << "["; for (int i = 0; i < sz; ++i) { if (i >= 256) { os << ", ..."; break; } if (i > 0) { os << ", "; } os << as[i]; } return os << "]"; }
template <class T> void pv(T a, T b) { for (T i = a; i != b; ++i) cerr << *i << " "; cerr << endl; }
template <class T> bool chmin(T &t, const T &f) { if (t > f) { t = f; return true; } return false; }
template <class T> bool chmax(T &t, const T &f) { if (t < f) { t = f; return true; } return false; }
////////////////////////////////////////////////////////////////////////////////
template <unsigned M_> struct ModInt {
static constexpr unsigned M = M_;
unsigned x;
constexpr ModInt() : x(0U) {}
constexpr ModInt(unsigned x_) : x(x_ % M) {}
constexpr ModInt(unsigned long long x_) : x(x_ % M) {}
constexpr ModInt(int x_) : x(((x_ %= static_cast<int>(M)) < 0) ? (x_ + static_cast<int>(M)) : x_) {}
constexpr ModInt(long long x_) : x(((x_ %= static_cast<long long>(M)) < 0) ? (x_ + static_cast<long long>(M)) : x_) {}
ModInt &operator+=(const ModInt &a) { x = ((x += a.x) >= M) ? (x - M) : x; return *this; }
ModInt &operator-=(const ModInt &a) { x = ((x -= a.x) >= M) ? (x + M) : x; return *this; }
ModInt &operator*=(const ModInt &a) { x = (static_cast<unsigned long long>(x) * a.x) % M; return *this; }
ModInt &operator/=(const ModInt &a) { return (*this *= a.inv()); }
ModInt pow(long long e) const {
if (e < 0) return inv().pow(-e);
ModInt a = *this, b = 1U; for (; e; e >>= 1) { if (e & 1) b *= a; a *= a; } return b;
}
ModInt inv() const {
unsigned a = M, b = x; int y = 0, z = 1;
for (; b; ) { const unsigned q = a / b; const unsigned c = a - q * b; a = b; b = c; const int w = y - static_cast<int>(q) * z; y = z; z = w; }
assert(a == 1U); return ModInt(y);
}
ModInt operator+() const { return *this; }
ModInt operator-() const { ModInt a; a.x = x ? (M - x) : 0U; return a; }
ModInt operator+(const ModInt &a) const { return (ModInt(*this) += a); }
ModInt operator-(const ModInt &a) const { return (ModInt(*this) -= a); }
ModInt operator*(const ModInt &a) const { return (ModInt(*this) *= a); }
ModInt operator/(const ModInt &a) const { return (ModInt(*this) /= a); }
template <class T> friend ModInt operator+(T a, const ModInt &b) { return (ModInt(a) += b); }
template <class T> friend ModInt operator-(T a, const ModInt &b) { return (ModInt(a) -= b); }
template <class T> friend ModInt operator*(T a, const ModInt &b) { return (ModInt(a) *= b); }
template <class T> friend ModInt operator/(T a, const ModInt &b) { return (ModInt(a) /= b); }
explicit operator bool() const { return x; }
bool operator==(const ModInt &a) const { return (x == a.x); }
bool operator!=(const ModInt &a) const { return (x != a.x); }
friend std::ostream &operator<<(std::ostream &os, const ModInt &a) { return os << a.x; }
};
////////////////////////////////////////////////////////////////////////////////
constexpr unsigned MO = 998244353;
using Mint = ModInt<MO>;
constexpr int LIM_INV = 400'010;
Mint inv[LIM_INV], fac[LIM_INV], invFac[LIM_INV];
void prepare() {
inv[1] = 1;
for (int i = 2; i < LIM_INV; ++i) {
inv[i] = -((Mint::M / i) * inv[Mint::M % i]);
}
fac[0] = invFac[0] = 1;
for (int i = 1; i < LIM_INV; ++i) {
fac[i] = fac[i - 1] * i;
invFac[i] = invFac[i - 1] * inv[i];
}
}
Mint binom(Int n, Int k) {
if (n < 0) {
if (k >= 0) {
return ((k & 1) ? -1 : +1) * binom(-n + k - 1, k);
} else if (n - k >= 0) {
return (((n - k) & 1) ? -1 : +1) * binom(-k - 1, n - k);
} else {
return 0;
}
} else {
if (0 <= k && k <= n) {
assert(n < LIM_INV);
return fac[n] * invFac[k] * invFac[n - k];
} else {
return 0;
}
}
}
#ifndef LIBRA_GRAPH_GRAPH_H_
#define LIBRA_GRAPH_GRAPH_H_
#include <assert.h>
#include <ostream>
#include <utility>
#include <vector>
using std::ostream;
using std::pair;
using std::vector;
////////////////////////////////////////////////////////////////////////////////
// neighbors of u: [pt[u], pt[u + 1])
struct Graph {
int n;
vector<pair<int, int>> edges;
vector<int> pt;
vector<int> zu;
Graph() : n(0), edges() {}
explicit Graph(int n_) : n(n_), edges() {}
void ae(int u, int v) {
assert(0 <= u); assert(u < n);
assert(0 <= v); assert(v < n);
edges.emplace_back(u, v);
}
void build(bool directed) {
const int edgesLen = edges.size();
pt.assign(n + 1, 0);
if (directed) {
for (int i = 0; i < edgesLen; ++i) {
++pt[edges[i].first];
}
for (int u = 0; u < n; ++u) pt[u + 1] += pt[u];
zu.resize(edgesLen);
for (int i = edgesLen; --i >= 0; ) {
zu[--pt[edges[i].first]] = edges[i].second;
}
} else {
for (int i = 0; i < edgesLen; ++i) {
++pt[edges[i].first];
++pt[edges[i].second];
}
for (int u = 0; u < n; ++u) pt[u + 1] += pt[u];
zu.resize(2 * edgesLen);
for (int i = edgesLen; --i >= 0; ) {
const int u = edges[i].first, v = edges[i].second;
zu[--pt[u]] = v;
zu[--pt[v]] = u;
}
}
}
inline int deg(int u) const {
return pt[u + 1] - pt[u];
}
inline int operator[](int j) const {
return zu[j];
}
friend ostream &operator<<(ostream &os, const Graph &g) {
os << "Graph(n=" << g.n << ";";
for (int u = 0; u < g.n; ++u) {
os << " " << u << ":[";
for (int j = g.pt[u]; j < g.pt[u + 1]; ++j) {
if (j != g.pt[u]) os << ",";
os << g[j];
}
os << "]";
}
os << ")";
return os;
}
};
////////////////////////////////////////////////////////////////////////////////
#endif // LIBRA_GRAPH_GRAPH_H_
// gg: bipartite graph between {vertex} and {biconnected component}
// (gg.n - n) biconnected components
// isolated point: not regarded as biconnected component (==> isolated in gg)
// f: DFS forest
struct Biconnected {
int n;
Graph g, f, gg;
Biconnected() : n(0), stackLen(0), zeit(0) {}
explicit Biconnected(int n_) : n(n_), g(n_), stackLen(0), zeit(0) {}
void ae(int u, int v) {
g.ae(u, v);
}
int stackLen;
vector<int> stack;
vector<int> par, rs;
int zeit;
vector<int> dis, fin, low;
vector<int> cntPar;
void dfs(int u) {
stack[stackLen++] = u;
dis[u] = low[u] = zeit++;
for (int j = g.pt[u]; j < g.pt[u + 1]; ++j) {
const int v = g[j];
if (par[u] == v && !cntPar[u]++) continue;
if (~dis[v]) {
if (low[u] > dis[v]) low[u] = dis[v];
} else {
f.ae(u, v);
par[v] = u;
rs[v] = rs[u];
dfs(v);
if (low[u] > low[v]) low[u] = low[v];
if (dis[u] <= low[v]) {
const int x = gg.n++;
for (; ; ) {
const int w = stack[--stackLen];
gg.ae(w, x);
if (w == v) break;
}
gg.ae(u, x);
}
}
}
fin[u] = zeit;
}
void build() {
g.build(false);
f = Graph(n);
gg = Graph(n);
stack.resize(n);
par.assign(n, -1);
rs.assign(n, -1);
zeit = 0;
dis.assign(n, -1);
fin.assign(n, -1);
low.assign(n, -1);
cntPar.assign(n, 0);
for (int u = 0; u < n; ++u) if (!~dis[u]) {
stackLen = 0;
rs[u] = u;
dfs(u);
}
f.build(true);
gg.build(false);
}
// Returns true iff u is an articulation point
// <=> # of connected components increases when u is removed.
inline bool isArt(int u) const {
return (gg.deg(u) >= 2);
}
// Returns w s.t. w is a child of u and a descendant of v in the DFS forest.
// Returns -1 instead if v is not a proper descendant of u
// O(log(deg(u))) time
int dive(int u, int v) const {
if (dis[u] < dis[v] && dis[v] < fin[u]) {
int j0 = f.pt[u], j1 = f.pt[u + 1];
for (; j0 + 1 < j1; ) {
const int j = (j0 + j1) / 2;
((dis[f[j]] <= dis[v]) ? j0 : j1) = j;
}
return f[j0];
} else {
return -1;
}
}
// Returns true iff there exists a v-w path when u is removed.
// O(log(deg(u))) time
bool isStillReachable(int u, int v, int w) const {
assert(0 <= u); assert(u < n);
assert(0 <= v); assert(v < n);
assert(0 <= w); assert(w < n);
assert(u != v);
assert(u != w);
if (rs[v] != rs[w]) return false;
if (rs[u] != rs[v]) return true;
const int vv = dive(u, v);
const int ww = dive(u, w);
if (~vv) {
if (~ww) {
return (vv == ww || (dis[u] > low[vv] && dis[u] > low[ww]));
} else {
return (dis[u] > low[vv]);
}
} else {
if (~ww) {
return (dis[u] > low[ww]);
} else {
return true;
}
}
}
};
////////////////////////////////////////////////////////////////////////////////
int N, M;
vector<int> A, B;
Biconnected C;
constexpr int E = 19;
constexpr int MAX_N = 400'010;
int dep[MAX_N];
int ppar[E][MAX_N];
int sum2[E][MAX_N];
int sum3[E][MAX_N];
void dfs(int u, int p) {
dep[u] = (~p) ? (dep[p] + 1) : 0;
ppar[0][u] = p;
for (int j = C.gg.pt[u]; j < C.gg.pt[u + 1]; ++j) {
const int v = C.gg[j];
if (p != v) {
dfs(v, u);
}
}
}
int lca(int u, int v) {
for (int e = E; --e >= 0; ) {
if (dep[u] - (1 << e) >= dep[v]) {
u = ppar[e][u];
}
if (dep[v] - (1 << e) >= dep[u]) {
v = ppar[e][v];
}
}
for (int e = E; --e >= 0; ) {
if (ppar[e][u] != ppar[e][v]) {
u = ppar[e][u];
v = ppar[e][v];
}
}
if (u != v) {
u = ppar[0][u];
v = ppar[0][v];
}
return u;
}
int main() {
prepare();
for (; ~scanf("%d%d", &N, &M); ) {
A.resize(M);
B.resize(M);
for (int i = 0; i < M; ++i) {
scanf("%d%d", &A[i], &B[i]);
--A[i];
--B[i];
}
C = Biconnected(N);
for (int i = 0; i < M; ++i) {
C.ae(A[i], B[i]);
}
C.build();
cerr<<"gg = "<<C.gg<<endl;
fill(dep, dep + C.gg.n, -1);
for (int u = 0; u < C.gg.n; ++u) if (!~dep[u]) {
dfs(u, -1);
}
fill(sum2[0], sum2[0] + C.gg.n, 0);
for (int u = N; u < C.gg.n; ++u) {
((C.gg.deg(u) == 2) ? sum2 : sum3)[0][u] = 1;
}
for (int e = 0; e < E - 1; ++e) {
for (int u = 0; u < C.gg.n; ++u) {
const int p = ppar[e][u];
if (~p) {
ppar[e + 1][u] = ppar[e][p];
sum2[e + 1][u] = sum2[e][u] + sum2[e][p];
sum3[e + 1][u] = sum3[e][u] + sum3[e][p];
} else {
ppar[e + 1][u] = -1;
sum2[e + 1][u] = sum2[e][u];
sum3[e + 1][u] = sum3[e][u];
}
}
}
int Q;
scanf("%d", &Q);
for (; Q--; ) {
int S, T, K;
scanf("%d%d%d", &S, &T, &K);
--S;
--T;
int s2 = 0, s3 = 0;
auto add = [&](int u, int d) -> void {
for (int e = E; --e >= 0; ) if (d >> e & 1) {
s2 += sum2[e][u];
s3 += sum3[e][u];
u = ppar[e][u];
}
};
const int l = lca(S, T);
add(S, dep[S] - dep[l]);
add(T, dep[T] - dep[l]);
if (l >= N) {
++((C.gg.deg(l) == 2) ? s2 : s3);
}
// cerr<<"s2 = "<<s2<<", s3 = "<<s3<<endl;
Mint ans = 0;
if (s2 + s3 <= K && K <= s2 + 2 * s3) {
ans = binom(s3, K - (s2 + s3));
}
printf("%u\n", ans.x);
}
}
return 0;
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 100
Accepted
time: 6ms
memory: 98700kb
input:
8 10 1 2 2 3 3 1 3 4 4 5 5 6 6 4 4 7 7 8 8 4 6 1 1 0 1 1 1 1 4 3 6 2 4 5 7 4 3 4 2
output:
1 0 1 2 1 0
result:
ok 6 numbers
Test #2:
score: 0
Accepted
time: 3ms
memory: 97128kb
input:
2 1 1 2 8 1 1 0 1 1 1 1 2 0 1 2 1 2 1 0 2 1 1 2 2 0 2 2 1
output:
1 0 0 1 0 1 1 0
result:
ok 8 numbers
Test #3:
score: 0
Accepted
time: 48ms
memory: 98224kb
input:
50 70 41 24 9 15 29 19 21 11 1 14 5 27 34 48 10 32 34 49 46 3 22 33 34 39 16 30 22 45 7 16 25 30 43 17 22 44 5 25 41 49 29 32 39 25 10 4 45 27 13 38 29 7 3 35 14 30 50 2 8 11 13 35 18 26 34 40 38 36 7 19 12 3 25 26 30 42 21 8 12 46 44 33 14 31 47 2 25 46 20 19 49 24 15 43 18 25 13 36 27 22 4 32 30 3...
output:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 4 0 0 15 5 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 2 0 0 0 0 0 6 0 0 0 0 0 0 0 0 7 0 0 0 0 3 0 6 0 0 0 0 7 0 6 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 15 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0...
result:
ok 200000 numbers
Test #4:
score: 0
Accepted
time: 8ms
memory: 97720kb
input:
99 147 26 66 27 92 75 90 91 64 69 15 70 61 52 59 3 86 41 99 47 71 26 43 99 83 43 80 42 69 4 75 66 71 68 38 31 57 5 91 74 2 90 4 32 11 1 31 77 5 76 8 12 60 79 42 48 89 22 14 36 76 45 91 43 65 99 86 69 16 85 11 19 28 15 52 49 85 84 68 28 85 93 68 16 15 42 9 71 51 72 92 84 2 13 50 9 44 97 78 11 60 98 3...
output:
0 0 0 231867712 1176 13983816 0 838535532 57966928 0 259558945 995677382 49 58518925 231867712 0 0 0 0 699660129 0 18424 0 0 0 0 425254360 596115770 0 0 0 0 435689908 0 0 578343994 351113550 0 0 1 186830027 578343994 211876 0 596115770 0 186830027 0 58518925 0 1906884 304945365 0 304945365 0 1 0 0 2...
result:
ok 99 numbers
Test #5:
score: -100
Time Limit Exceeded
input:
199999 299997 46838 7499 94674 132821 113340 39783 26895 102985 48012 197970 142680 5947 103806 184307 136126 111090 130225 128927 158116 75097 24205 199579 53104 138584 43659 53794 139767 62161 93131 22718 129300 168198 49873 179193 194655 168999 113749 118408 37725 48137 151840 84343 111148 8100 1...