A graph is called functional if every node has exactly one outgoing edge, and no edge points from a node to itself (no self-loops).
Given a functional graph on nodes, we can choose a set of special nodes. A selection is good if every node in the graph is either special, or reachable from a special node in 1 or more steps.
Given and , count the number of good selections, summed over all possible functional graphs on nodes, modulo .
- [From experience] the graph is a collection of cycles with trees attached to them.
- Combinatorics + DP + recursion?
- choose — does it matter which you choose? (By symmetry, probably not.)
- , so we need or .
- This seems hard.
- All leaves have to be special.
- [Exploit symmetry / constraints] A lot of symmetry here — does some formula simplify?
- Flows?
IdeaLeaves and cycles, direct recursion
Any graph where each node has out-degree 1 is a collection of cycles with trees hanging off them.
I knew this structure from prior problems — but you can also [Draw a Picture] and [Examine Examples] to convince yourself: keep following the out-edges from any node and you must eventually revisit a node. That's a cycle.
If any leaf (a node with no incoming edges) is not special, the selection is bad: nothing can reach a leaf, so every leaf must be special.
Symmetrically, if some component is a pure cycle (no trees attached), then at least one node on that cycle must be special — otherwise the whole component is unreachable.
At this point the problem still seemed really hard given the constraint.
Ignore the requirement — can I solve this at all, in or , to get a feel?
Problems like this usually work by deciding what happens to node , then recursing on the graph with nodes.
This leads to a recurrence. Let be the count over all functional graphs with nodes, special nodes, and leaves. Then, splitting on what the -th node is:
F(n,m,k) = {n'th is a leaf, pointing to a previous leaf}
+ {n'th is a leaf, pointing to a previous non-leaf}
+ {n'th is not a leaf}
= F(n-1,m,k) * k + F(n-1,m-1,k-1) * (n-k-1) + ...To be honest, I couldn't figure out the rest of the recurrence for the case where node is not a leaf. We have some good core ideas, but this recurrence is too complex to work with.
IdeaPrüfer sequences — what if it were a tree?No Solution
The cycles were confusing me, so I started wondering: could I solve this on a tree instead of a loopy functional graph? How many trees are there with nodes and leaves?
After Googling a little, I found this is related to Prüfer sequences.
A Prüfer sequence encodes a labeled tree on nodes as a sequence of numbers: repeatedly take the smallest-numbered leaf, remove it, and record its neighbor's label, until 2 nodes remain.
These sequences are a bijection: every sequence of numbers from corresponds to exactly one labeled tree, giving Cayley's formula for the number of labeled trees. For rooted trees the same procedure runs until only the root remains, giving sequences of length and rooted trees.
To count trees by their number of leaves, ask: can you read off the leaves from the Prüfer sequence?
In the rooted-tree encoding, the leaves of the tree are exactly the labels that do not appear in the Prüfer sequence — a leaf is never recorded as anyone's parent, while every internal node must be.
So let be the number of rooted trees with nodes and leaves — equivalently, the number of sequences of length over in which exactly labels never appear.
Pretend we have boxes — the labels that do appear. We must assign each of the sequence slots to one of the boxes so that no box is empty. Partitioning items into non-empty groups is exactly the Stirling numbers of the second kind — something I recognized from experience.
(choose which labels are leaves; partition the slots into non-empty groups; assign the groups to actual labels.)
If we could compute the Stirling numbers, the tree version of the problem would follow by summing over the number of leaves , forcing all leaves to be special and choosing the remaining special nodes freely:
(Factorials up to and their modular inverses can be precomputed, making each binomial .)
So the hard part is computing the Stirling numbers. There are two classic routes:
Consider item : either it is a singleton subset, or it joins one of the existing subsets:
S(n,k) = S(n-1,k-1) + k * S(n-1,k)Correct, but time and space — too slow here.
Number the boxes and assign each of the items a box: ways, but some boxes may be empty. Let be the assignments where box is empty; subtract the union via inclusion-exclusion (see the Aside below), then divide by to unlabel the boxes:
Defining and , both computable for all in , the values for all at once form a convolution — computable in with the Fast Fourier Transform (FFT).
A note on that last step: FFT is a relatively involved algorithm, and in another world I'd build it up here the way I do inclusion-exclusion below — but since we're about to move on from trees entirely, that would be a distraction. I did try to simplify to avoid the FFT, but the double sum doesn't separate: the inner index stays coupled to through the term, which is exactly the shape a convolution exists to handle.
With some work this extends to forests by adding a dummy root node . But I need functional graphs, not forests — good time to move on.
We can use bijections from number sequences to trees (or forests, or graphs), and count sequences with certain properties instead of counting graphs directly.
Inclusion-exclusion can turn these counting problems into explicit closed-form sums over one index — which is once factorials are precomputed.
AsideFormalizing Inclusion-Exclusion
A technique used briefly above, and heavily below, is inclusion-exclusion. I generally understand it, but it's worth formalizing.
Let and be two sets of outcomes — possibly overlapping. To count outcomes where at least one of them occurs:
Applying this repeatedly generalizes to more sets:
and in general, for sets :
The sign alternates with the number of sets intersected.
Why is this useful? In many problems, counting the intersection ( AND AND ) is far easier than counting the union ( OR OR ). If you can write a simple formula for the intersection of any subset of your sets, inclusion-exclusion hands you the union.
In the Stirling-number problem: let = assignments where box is empty. We want no box empty, i.e. . Any intersection of of these sets is trivial to count — it's just , assignments avoiding boxes — which yields the formula above.
The trick to inclusion-exclusion is choosing the events so that describing any intersection of them is easy.
IdeaGeneralizing to functional graphs
Idea 2 was insightful but only handles trees. Functional graphs have cycles. It turns out the core approach — write the graph as a sequence and count sequences with the right properties — still works, together with inclusion-exclusion.
Instead of Prüfer sequences, work with what we've got directly: each node points to exactly one other node, so the sequence — where is the node that points to, — uniquely determines the functional graph. There are such sequences.
A node is a leaf exactly when it never appears in the sequence — the same trick as reading leaves off a Prüfer sequence, applied to the functional graph's own pointer sequence. So we can do inclusion-exclusion directly on "node never appears."
By symmetry, first choose the special nodes: ways; say they are nodes . A selection fails on leaves if some non-special node is a leaf. Let (for ) be the set of sequences where node is a leaf.
For a fixed set of forced leaves, count the sequences: each forced leaf must point somewhere (but not to itself or another forced leaf, which must stay leaves) — choices each — and each of the other nodes must avoid itself and all leaves — choices each. So by inclusion-exclusion, the number of sequences with no bad leaves is:
and the candidate answer is times that. We're making a ton of progress — but this is still wrong: it ignores the pure cycles. A component that is a bare cycle with no special node on it is unreachable, and nothing above accounts for that.
Let's tackle that next.
IdeaPure cycles and derangements
If the graph consisted of only pure cycles, it would look exactly like a permutation — any permutation decomposes into disjoint cycles. Cycle-counting on permutations is the territory of the (unsigned) Stirling numbers of the first kind. Useful, or a distraction...
Since self-loops are forbidden, we need permutations with no fixed points — these are called derangements. (The first-kind Stirling numbers aren't directly applicable.)
From here on, derangement means a permutation with no fixed points — equivalently, a functional graph consisting only of pure cycles of length . The equivalence: in a permutation every node has out-degree 1 and in-degree 1, so the graph is exactly a disjoint union of cycles, and "no fixed points" is precisely "no self-loops."
It turns out derangements are counted by — you guessed it — inclusion-exclusion. Let be the permutations where element is a fixed point. Then:
(the middle step expands ). This is computable in — or all values in one sweep.
Side note: that last sum is the power series of at , so — in fact exactly, for all . (We work modulo , so we use the sum, not the rounding trick.)
Using inclusion-exclusion, all derangement counts can be precomputed in total time.
This counts the pure-cycle graphs. But our problem also chooses special nodes, and demands every cycle contain one. So the next question is how to count derangement–selection pairs where no cycle is missed — still on pure cycles only, which remains a useful stepping stone before combining everything.
IdeaCounting good selections on pure cycles
Idea 4 counts pure-cycle graphs; now, on a graph of only pure cycles (a derangement), count selections of special nodes such that every cycle contains at least one of them. This is the part that stumped me.
I was stuck here for a while and looked at the solution — so this section is a reverse-engineering of the logic. I completely missed the key observation, and I think you'll find it fun to reconstruct.
Given how far we've come, we want inclusion-exclusion. But on what events?
My first attempt: let be the derangement–selection pairs where node is trapped in a bad cycle (one containing no special node). Then the answer would be ... and this is where I got stuck. I could not write down clean formulas for the intersections .
Inclusion-exclusion only works when you have a clean way to count the intersections. If the intersections are gnarly, you've chosen the wrong events.
If we want to penalize "bad cycles," what should the events be?
The cycles ARE the events. Fix the special nodes. For each possible cycle containing no special node (a bad candidate), let be the set of derangements in which appears as one of the cycles. There may be a gazillion candidate cycles, but the answer is simply over all bad candidates — and these intersections are easy: once you decide that specific cycles appear, all their nodes' edges are fixed, and the remaining nodes just form a derangement among themselves.
Concretely: an intersection of disjoint bad cycles covering nodes fixes those nodes entirely, and the other nodes can be deranged freely among themselves: ways. First choose which non-special nodes sit in the bad cycles — ways — then let count the ways to arrange those nodes into exactly cycles (each of length ). Inclusion-exclusion gives:
Pull everything independent of out of the inner sum:
If we could kill that inner sum, we'd have a single loop. First, satisfies a recursion (good ol' fashioned recursion — no inclusion-exclusion needed): let be the length of the cycle containing the -th node — choose its companions and arrange the cycle:
Not obviously simpler — but substitute it into the alternating sum. Writing :
for all .
Induction on . Base cases: (the empty arrangement), and (one node can't form a cycle of length ). For , assume for all . The summand telescopes: for ,
so
and therefore
So the pure-cycle answer collapses to a single sum:
with derangements and factorials precomputed in . Notice again: and are treated as fixed constants; we only sum over .
In Idea 3 we got the core idea for components with leaves. Here we got the core idea for cycles. Can we put it all together?
IdeaPutting it all togetherAC
The final solution combines Ideas 3 and 5 into one inclusion-exclusion over all the bad events at once.
Fix and ; choose the special nodes ( ways, WLOG nodes ), and represent each graph as its pointer sequence . The bad events:
- for each non-special node : node is a leaf (appears nowhere in the sequence);
- for each special-free cycle : the nodes of form exactly that cycle, and nothing outside points into it (a pure bad cycle).
A selection is bad iff at least one of these occurs, so we subtract from via inclusion-exclusion. Consider an intersection with leaf-events and cycle-events covering nodes (sign ):
- choose the nodes for the bad cycles ( ways), then form the cycles ( ways) — their edges are now fixed;
- each of the forced leaves points anywhere except itself, the other leaves, and the cycle nodes: choices;
- each of the remaining free nodes avoids itself, the leaves, and the cycle nodes: choices.
Now simplify, in three moves:
- Replace the inner -sum with (Key Observation 6).
- Substitute and regroup — the summand depends on only through and the leftover , and the binomials merge as .
- Pull the -only factors out of the inner sum.
Split the inner sum using into a plain part and an -weighted part. Both collapse:
By the Binomial Theorem with , :
and by differentiating the Binomial Theorem in — giving — the weighted sum collapses too:
The binomial theorem is standard; the derivative trick — differentiate a known identity to collapse an index-weighted sum — is one I'd seen before in generating-function problems, and [Write It Out] is what surfaced it here.
Substituting both back:
Factor the bracket: , and since , we get , which merges with the into a single power:
After the inclusion-exclusion miraculously telescopes and simplifies, we sum over a single index , treating and as constants, using precomputed factorials and fast exponentiation for . Total: (the from the modular exponentiations).
Review
The number of good (graph, selection) pairs, modulo , is
computable in . The path there, in key observations:
- Structure. A functional graph is cycles with trees attached. A selection is good iff every leaf is special and every pure cycle contains a special node. [1][2][3]
- Sequences, not graphs. Encode each graph as its pointer sequence ; a node is a leaf iff its label never appears in the sequence. [4]
- Inclusion-exclusion needs countable intersections. Choose the events so that intersecting any subset of them is easy to count.
- The cycles are the events. One event per special-free candidate cycle ("this exact cycle appears, untouched") freezes its nodes and leaves a clean sub-problem — intersections become trivial, even combined with the leaf events. [5]
- The master sum. Intersecting leaf-events with bad cycles covering nodes — where counts the ways to arrange chosen nodes into exactly cycles of length — gives:
- The alternating cycle-sum collapses: , by a telescoping induction. [6]
- The binomial theorem — and its derivative — kill the remaining inner sum, leaving the single-sum formula above. [7]
Pseudocode:
MAXN = 10**6 + 5
PRIME = 998244353
# O(MAXN) precomputation
fact = [1] * MAXN
for i in range(1, MAXN):
fact[i] = fact[i-1] * i % PRIME
invfact = [modinv(f) for f in fact] # modinv via pow(f, PRIME-2, PRIME)
def choose(n, k):
if k < 0 or k > n: return 0
return fact[n] * invfact[k] % PRIME * invfact[n-k] % PRIME
def solve(n, m):
ans = 0
for a in range(0, n - m + 1):
term = choose(n - m, a) * pow(n - 1 - a, n - 1, PRIME) % PRIME
ans = (ans - term if a % 2 else ans + term) % PRIME
ans = ans * (n - 1) % PRIME
ans = ans * choose(n, m) % PRIME
return ansReferences
Learning points. In the end this problem was an exercise in inclusion-exclusion, and in being very careful about how you count and decompose the sets.
I got quickly to "look at the leaves and the pure cycles," and tried solving them separately — then got completely stumped on the pure cycles. Part of it was that I kept looking for a recursion on the -th or -th node, but the recursion was tricky to get right, if it exists at all. Just as with Stirling numbers of the second kind, some counting problems admit both a recursion and an inclusion-exclusion formula — and they have very different computational profiles.
Inclusion-exclusion works when you have an easy time intersecting interesting configurations but a hard time with the union . Overlapping, conflicting configurations are fine — as long as every subset of events with a known "size" has a countable intersection, the machinery does the rest.
The hardest part for me was recognizing how to run inclusion-exclusion on the pure cycles. I kept choosing "number of nodes trapped in bad cycles" as the quantity to sum over, and no formula worked — there was no clean way to AND together "these particular nodes are in bad cycles." The aha came from making the cycles themselves the events: once a cycle is required to appear, its nodes are frozen and everything else derangles freely, so intersections become easy — even when combined with the leaf events. The resulting sums looked terrifying, then telescoped and collapsed.
I don't think it will always be that clean — but sometimes you just have to [Write It Out], and watch the formula simplify. Notably, and factored out as constants throughout: we never needed the answer for all , just one final sum over a single index.
I feel I learned a lot about inclusion-exclusion from this problem — and about how seemingly intractable counting problems fall apart once you pick the right events.
Topics: inclusion-exclusion · permutations, derangements, cycle notation · combinatorics, binomial coefficients · recursion & induction · modular arithmetic · fast exponentiation
Related: Stirling numbers (first & second kind) · Prüfer sequences & Cayley's formula · counting labeled trees by leaves