简单子环图 题解
简单子环图 题解
题意
\(~~~~\) 求有多少 \(n\) 个点 \(m\) 条边的有标号无向图是一个环的子图。
\(~~~~\) \(1\leq n,m\leq 10^5\).
题解
\(~~~~\) 比较中规中矩的一道题,但输在了非生成函数部分,记录一下。
\(~~~~\) 显然图的形态应该是若干条链,所以我们考虑连通块。显然 \(n\) 个点 \(m\) 条边有 \(n-m\) 个连通块。(下文记其为 \(k\) )设划分出的连通块大小分别为 \(Siz_1,Siz_2,\dots,Siz_k\) ,那么显然划分进连通块的方案数就是:
\[\dfrac{n!}{\prod_{i=1}^n Siz_i!}
\]
\(~~~~\) (把连通块视作颜色比较好想)
\(~~~~\) 然后假设大小为 \(i\) 的连通块的连边方案为 \(p_i\) ,则:
\[
p_i=
\left\{\begin{array}{l}
1~~~~ i=1\\
\dfrac{i!}{2} ~~~~ \text{Otherwise.}
\end{array}\right.
\]
\(~~~~\) 对我就是输在了这里(
\(~~~~\) 所以我们可以写出最后的答案:
\[\dfrac{n! \prod p_i}{\prod_{i=1}^n Siz_i!\times k!}
\]
\(~~~~\) 常数提出来,利用 \(\sum Siz=n\) 自然地构造生成函数:
\[F(x)=\dfrac{p_i}{i!}x^i
\]
\(~~~~\) 把 \(p_i\) 代进去,它的数列应该是:\(x+\sum_{i=2}^\infty \dfrac{1}{2}x^i\)
\(~~~~\) 后面部分的封闭形式众所周知,所以是 \(x+x^2\dfrac{\frac{1}{2}}{1-x}=\dfrac{x}{1-x}(1-\dfrac{1}{2}x)\) 。
\(~~~~\) 有 \(k\) 个连通块,所以卷 \(m\) 次,自然而然地打开,得到 \(x^n\) 项系数为:
\[\sum_{i=0}^k \begin{pmatrix} k\\i \end{pmatrix}\times (-\dfrac{1}{2})^i\times \begin{pmatrix} i+k-1\\k-1 \end{pmatrix}
\]
\(~~~~\) 代入,然后再乘上上面分离的常数即可。
代码
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const ll MOD=1e9+7;
inline ll Add(ll a,ll b){return (1ll*a+b)%MOD;}
inline ll Dec(ll a,ll b){return (1ll*a-b+MOD)%MOD;}
inline ll Mul(ll a,ll b){return 1ll*a*b%MOD;}
ll qpow(ll a,ll b)
{
ll ret=1;
while(b)
{
if(b&1) ret=Mul(ret,a);
b>>=1;a=Mul(a,a);
}
return ret;
}
const ll Inv2=qpow(2,MOD-2);
ll Fac[100005],Inv[100005],Pow[100005];
inline ll C(ll n,ll r){if(n<r) return 0;return Mul(Fac[n],Mul(Inv[r],Inv[n-r]));}
int main() {
ll T,n,m;
Fac[0]=Pow[0]=1;
for(ll i=1;i<=100000;i++) Fac[i]=Mul(Fac[i-1],i),Pow[i]=Mul(Pow[i-1],Dec(MOD,Inv2));
Inv[100000]=qpow(Fac[100000],MOD-2);
for(ll i=99999;i>=0;i--) Inv[i]=Mul(Inv[i+1],i+1);
scanf("%lld",&T);
while(T--)
{
scanf("%lld %lld",&n,&m);
if(n==m) {printf("%lld\n",Mul(Fac[n-1],Inv2));continue;}
if(n<m) {printf("0\n");continue;}
ll k=n-m,Ans=0;
for(ll i=0;i<=k;i++)
Ans=Add(Ans,Mul(C(k,i),Mul(Pow[i],C(n-i-1,k-1))));
printf("%lld\n",Mul(Ans,Mul(Fac[n],Inv[k])));
}
return 0;
}