Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
By symmetry, do not count every starting set separately. Fix one specific set of size , count graphs where it works, then multiply by .
Compress the graph into strongly connected components. A set reaches everything iff every source SCC in this DAG contains at least one vertex of .
In a loopless functional graph, source SCCs are only two types: an indegree-zero single vertex, or a directed cycle with no incoming edge from outside. A bad source SCC is one of these using only non-selected vertices.
Use inclusion-exclusion over bad source SCCs. If a chosen bad collection covers non-selected vertices, the outside vertices each have choices for their outgoing edge.
The only annoying subcount is over permutations on those chosen vertices: fixed points represent indegree-zero singletons, nontrivial cycles represent source cycles. Its signed sum is , which collapses the answer to one simple summation.
Fix a starting set with . All labels are symmetric, so after counting the number of graphs where this fixed is successful, the final answer is
Call vertices in key vertices, and all other vertices non-key vertices.
Look at the SCC condensation DAG of the functional graph. A set of starts reaches every vertex iff every source SCC of this DAG contains a start. This is the standard DAG fact: every SCC is reachable from some source SCC, and no one can enter a source SCC from outside.
In a loopless functional graph, SCCs are directed cycles of length at least , plus singleton vertices not on cycles. Therefore a bad source SCC is either:
So is successful iff there are no bad source SCCs.
Now use inclusion-exclusion over bad source SCCs. Suppose we choose a collection of bad source SCCs covering exactly non-key vertices. First choose those vertices in
ways.
For the chosen vertices, describe the chosen bad SCCs as a permutation:
Each chosen SCC contributes a factor from inclusion-exclusion.
Let a permutation on the chosen vertices have cycles and fixed points. The contribution of its internal structure is
Why the ? A fixed point is not a self-loop in the real graph. It represents an indegree-zero singleton, so its outgoing edge must go outside the chosen vertices, giving choices. Nontrivial cycle vertices have their outgoing edges fixed by the cycle.
Every vertex outside the chosen vertices must avoid pointing into them, otherwise the chosen SCC would not be a source. It also cannot point to itself. Thus each outside vertex has
choices, for a factor
So we need the signed permutation sum
Compute it by cycle generating functions. A fixed point has weight , and every cycle of length has weight . Therefore
For a fixed , set . Since
we get
Extracting the coefficient gives
for , and the same final product below also works for . Therefore the contribution for this becomes
Summing over all possible :
Finally,
modulo .
This also handles : the sum has only , so it becomes , exactly the number of loopless functional graphs. For , this is , which is right because there is no valid outgoing edge. Tiny edge case, but it matters; off-by-one hell loves this stuff.
Precompute factorials and inverse factorials up to the maximum . For each test case, evaluate the sum in terms, using fast exponentiation for each power. Since the total over all tests is at most , this is easily fine.
Complexity:
with memory, where is the maximum input .
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll MOD = 998244353;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
ll modpow(ll a, ll e) {
a %= MOD;
ll r = 1;
while (e > 0) {
if (e & 1) r = r * a % MOD;
a = a * a % MOD;
e >>= 1;
}
return r;
}
int main() {
setIO();
int t;
cin >> t;
vector<pair<int, int>> tests(t);
int max_n = 0;
for (auto &[n, m] : tests) {
cin >> n >> m;
max_n = max(max_n, n);
}
vector<ll> fact(max_n + 1), invfact(max_n + 1);
fact[0] = 1;
for (int i = 1; i <= max_n; i++) fact[i] = fact[i - 1] * i % MOD;
invfact[max_n] = modpow(fact[max_n], MOD - 2);
for (int i = max_n; i >= 1; i--) invfact[i - 1] = invfact[i] * i % MOD;
auto C = [&](int n, int k) -> ll {
if (k < 0 || k > n) return 0;
return fact[n] * invfact[k] % MOD * invfact[n - k] % MOD;
};
for (auto [n, m] : tests) {
int p = n - m;
ll sum = 0;
for (int i = 0; i <= p; i++) {
ll term = C(p, i) * modpow(n - i - 1, n - 1) % MOD;
if (i & 1) sum = (sum - term + MOD) % MOD;
else sum = (sum + term) % MOD;
}
ll ans = C(n, m) * ((n - 1) % MOD) % MOD * sum % MOD;
cout << ans << '\n';
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll MOD = 998244353;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
ll modpow(ll a, ll e) {
a %= MOD;
ll r = 1;
while (e > 0) {
if (e & 1) r = r * a % MOD;
a = a * a % MOD;
e >>= 1;
}
return r;
}
int main() {
setIO();
int t;
cin >> t;
vector<pair<int, int>> tests(t);
int max_n = 0;
for (auto &[n, m] : tests) {
cin >> n >> m;
max_n = max(max_n, n);
}
vector<ll> fact(max_n + 1), invfact(max_n + 1);
fact[0] = 1;
for (int i = 1; i <= max_n; i++) fact[i] = fact[i - 1] * i % MOD;
invfact[max_n] = modpow(fact[max_n], MOD - 2);
for (int i = max_n; i >= 1; i--) invfact[i - 1] = invfact[i] * i % MOD;
auto C = [&](int n, int k) -> ll {
if (k < 0 || k > n) return 0;
return fact[n] * invfact[k] % MOD * invfact[n - k] % MOD;
};
for (auto [n, m] : tests) {
int p = n - m;
ll sum = 0;
for (int i = 0; i <= p; i++) {
ll term = C(p, i) * modpow(n - i - 1, n - 1) % MOD;
if (i & 1) sum = (sum - term + MOD) % MOD;
else sum = (sum + term) % MOD;
}
ll ans = C(n, m) * ((n - 1) % MOD) % MOD * sum % MOD;
cout << ans << '\n';
}
return 0;
}