Challenge: How Many Trees?
Subdomeniu: Combinatorics (combinatorics)
Scor cont: 100.0 / 100
Submission status: Accepted
Submission score: 1.0
Submission ID: 464817523
Limbaj: cpp14
Link challenge: https://www.hackerrank.com/challenges/how-many-trees/problem
Cerinta
You are given two integers $N$ and $L$. Compute the number of unrooted labelled trees with exactly $N$ nodes and exactly $L$ leafs. This number can be huge, so please output it's modulo $10^9+7$.
Input Format
The first line of input consists of two space separated integers $N$ and $L$.
**Constraints**
$1 \leq L < N \leq 10^6$
Output Format
Display an answer to the problem on first line of the output.
Cod sursa
#include <bits/stdc++.h>
using namespace std;
/*
* How Many Trees? (HackerRank)
*
* Count the number of labeled (1..n) undirected trees with exactly l leaves.
* Answer modulo MOD (assumed 1e9+7 as in the original problem).
*
* Key fact (Prufer codes):
* Each labeled tree on n vertices <-> Prufer sequence of length n-2 over labels 1..n.
* Vertex v has degree deg(v) = 1 + (number of occurrences of v in the Prufer code).
* Leaves are exactly the labels that appear 0 times in the Prufer sequence.
*
* Therefore, a tree with exactly l leaves means exactly k = n-l labels appear at least once
* in the code. Choose which l labels are missing, and then count surjections of length (n-2)
* onto the remaining k labels.
*
* Count of surjections from an N-set onto k labels:
* k! * S(N,k) = sum_{i=0..k} (-1)^i * C(k,i) * (k-i)^N
*
* So final answer:
* ans = C(n,l) * sum_{i=0..k} (-1)^i C(k,i) (k-i)^(n-2) (mod MOD)
*/
static const long long MOD = 1000000007LL;
static long long mod_pow(long long a, long long e) {
long long r = 1 % MOD;
a %= MOD;
while (e > 0) {
if (e & 1LL) r = (__int128)r * a % MOD;
a = (__int128)a * a % MOD;
e >>= 1LL;
}
return r;
}
static long long mod_inv(long long a) {
return mod_pow(a, MOD - 2);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
long long n, l;
if (!(cin >> n >> l)) return 0;
if (n == 0) {
cout << 0 << "\n";
return 0;
}
if (n == 1) {
// A single vertex has degree 0; by the standard definition "leaf = degree 1",
// the only valid leaf count is 0.
cout << ((l == 0) ? 1 : 0) << "\n";
return 0;
}
if (l < 0 || l > n) {
cout << 0 << "\n";
return 0;
}
long long N = n - 2; // length of Prufer code
long long k = n - l; // number of non-leaves (labels used at least once)
if (k < 0) {
cout << 0 << "\n";
return 0;
}
// Precompute factorials up to n.
int nn = (int)n;
vector<long long> fact(nn + 1), invfact(nn + 1);
fact[0] = 1;
for (int i = 1; i <= nn; i++) fact[i] = (__int128)fact[i - 1] * i % MOD;
invfact[nn] = mod_inv(fact[nn]);
for (int i = nn; i >= 1; i--) invfact[i - 1] = (__int128)invfact[i] * i % MOD;
auto C = [&](long long a, long long b) -> long long {
if (b < 0 || b > a) return 0;
return (long long)((__int128)fact[(int)a] * invfact[(int)b] % MOD * invfact[(int)(a - b)] % MOD);
};
long long choose_n_l = C(n, l);
long long sum = 0;
for (long long i = 0; i <= k; i++) {
long long comb = C(k, i);
long long base = (k - i) % MOD;
long long pw;
if (N == 0) {
// treat 0^0 as 1
pw = 1;
} else {
pw = mod_pow(base, N);
}
long long term = (__int128)comb * pw % MOD;
if (i & 1LL) {
sum -= term;
if (sum < 0) sum += MOD;
} else {
sum += term;
if (sum >= MOD) sum -= MOD;
}
}
long long ans = (__int128)choose_n_l * sum % MOD;
cout << ans << "\n";
return 0;
}
HackerRank Combinatorics – How Many Trees?
