【The 2018 ACM-ICPC Asia Qingdao Regional Contest】Sub-cycle Graph
题目描述
[题目链接](http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5826)
给定 $n$ 个点,你需要在里面连上 $m$ 条无向边,不能有重边或自环
对于每种连边方式都对应着一张无向图,求有多少种不同的无向图,使得它可以通过加入若干条边后使得整张图变成一个环
数据范围:$3 \le n \le 10^5, 0 \le m \le {n \choose 2}$
题解
那么就相当于只能连出链,由于每加入一条边,就会少一个点,因此一共有 $k=n-m$ 条链
设 $n$ 个点连成一条链的方案数为 $l_n$,则:
$$
l_n=\begin{cases}
1 & \quad (n=1) \\
\frac{n!}{2} & \quad (n > 1)
\end{cases}
$$
考虑链的指数型生成函数 $L(x)$,即:
$$
L(x)=\sum_{n \ge 1} l_n \frac{x^n}{n!}=x+ \frac{x^2}{2} \sum_{n \ge 0} x^n=\frac{x}{1-x}\left(1-\frac{x}{2}\right)
$$
考虑答案的指数型生成函数 $F_k(x)$,即:
$$
F_k(x)=\sum_{n \ge 1} f_{n,k} \frac{x^n}{n!}=L^{k}(x)=\frac{x^k}{(1-x)^k} \left(1-\frac{x}{2}\right)^k
$$
由于链之间也应该是无顺序的,因此还需要除以 $k!$,答案就是:
$$
\frac{[x^n]L^k(x)}{k!}
$$
由于:
$$
\begin{aligned}
&\left( 1-\frac{x}{2} \right)^k \\
=&\sum_{i=0}^{k} {k \choose i} \left(-\frac{1}{2}\right)^i x^i \\
\end{aligned}
$$
同时 $\frac{1}{(1-x)^k}$ 相当于求了 $k$ 次前缀和,对序列 $p$ 求 $k+1$ 次前缀和后 $p'_n=\sum_{i=0}^{n} {k+i \choose k}p_{n-i}$
代码
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 const int mod = 1e9 + 7, N = 1e5 + 10; 6 7 ll pw(ll a, ll b) { 8 ll r = 1; 9 for( ; b ; b >>= 1, a = a * a % mod) { 10 if(b & 1) { 11 r = r * a % mod; 12 } 13 } 14 return r; 15 } 16 17 ll getinv(ll n) { 18 return pw(n, mod - 2); 19 } 20 21 ll fac[N], invfac[N]; 22 void init(int n) { 23 fac[0] = invfac[0] = 1; 24 for(int i = 1 ; i <= n ; ++ i) { 25 fac[i] = fac[i - 1] * i % mod; 26 } 27 invfac[n] = pw(fac[n], mod - 2); 28 for(int i = n - 1 ; i ; -- i) { 29 invfac[i] = invfac[i + 1] * (i + 1) % mod; 30 } 31 } 32 ll C(int n, int m) { 33 return n < m || m < 0 ? 0 : fac[n] * invfac[m] % mod * invfac[n - m] % mod; 34 } 35 36 ll n, m; 37 const int inv2 = (mod + 1) / 2; 38 void runprog() { 39 scanf("%lld%lld", &n, &m); 40 if(n < m) { 41 puts("0"); 42 } else if(n == m) { 43 printf("%lld\n", fac[n - 1] * inv2 % mod); 44 } else { 45 ll res = 0; 46 ll k = n - m; 47 ll prod = 1; 48 for(int i = m ; ~ i ; -- i) { 49 res += C(k + i - 1, i) * C(k, m - i) % mod * prod % mod; 50 res %= mod; 51 prod = prod * -inv2 % mod; 52 } 53 res = res * fac[n] % mod * invfac[k] % mod; 54 printf("%lld\n", (res % mod + mod) % mod); 55 } 56 } 57 58 int main() { 59 init(N - 1); 60 int t; scanf("%d", &t); 61 while(t --) { 62 runprog(); 63 } 64 }