L - Sub-cycle Graph
Tutorial
A graph is a sub-cycle graph, if every connected component is either a single vertex or a chain. Of course, if this graph is actually a big cycle, it is also a sub-cycle graph. Let's first deal with some special cases:
- , these is only one such graph.
- , no solution.
- , all vertices must form a big cycle. Without loss of generality, let vertex be the "beginning" of the cycle, it is not hard to calculate that there are ways to form a cycle. We divide here because the cycle is not directional.
What remains is the case where . Because there is no cycle in each connected component, we have connected components.
We enumerate from to , indicating that there are chains in these connected components (that is to say, there are single vertex), and we choose vertices as the endpoints of the chains. The number of ways to divide vertices into groups where each group has exactly vertices (that is, the number of ways to put different balls into indistinguishable boxes) can be calculated as
You can imagine the grouping process like this: after sorting the vertices, each time group the smallest vertex and another vertex together. Thus the number of ways is .
Next, we need to distribute all vertices, except the vertices which form a connected component by themselves and the endpoints of the chains, into the chains. Because the order of vertices in a chain is crucial, we first choose a permutation of the vertices, and then divide them into groups where empty groups are allowed (that is, insert partitions among balls). The number of ways can be calculated as
So the final answer is
The time complexity is .
Solution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 | #include <bits/stdc++.h>
#define MAXN ((int) 1e5)
#define MOD ((int) 1e9 + 7)
using namespace std;
int n;
long long ans, m;
long long fac[MAXN + 10], ifac[MAXN + 10];
long long C(int a, int b) {
return fac[a] * ifac[b] % MOD * ifac[a - b] % MOD;
}
void solve() {
scanf("%d%lld", &n, &m);
if (m == 0) printf("1\n");
else if (m > n) printf("0\n");
else if (m == n) printf("%lld\n", fac[n - 1] * ifac[2] % MOD);
else {
ans = 0;
// f is the \prod in the tutorial
long long f = 1;
for (int i = 1; i <= n - m; i++) {
if (m + i < i * 2) continue;
long long t = C(m + i, i * 2) * f % MOD;
f = f * (i * 2 + 1) % MOD;
t = t * fac[m - i] % MOD;
t = t * C(m - 1, i - 1) % MOD;
ans = (ans + C(n, n - m - i) * t) % MOD;
}
printf("%lld\n", ans);
}
}
int main() {
fac[0] = 1;
for (int i = 1; i <= MAXN; i++) fac[i] = fac[i - 1] * i % MOD;
ifac[0] = ifac[1] = 1;
for (int i = 2; i <= MAXN; i++) ifac[i] = (MOD - MOD / i) * ifac[MOD % i] % MOD;
for (int i = 2; i <= MAXN; i++) ifac[i] = ifac[i - 1] * ifac[i] % MOD;
int tcase; scanf("%d", &tcase);
while (tcase--) solve();
return 0;
}
|