青岛金牌题补题
L. Sub-cycle Graph
题意:给你n个点,m条边,问有多少种组合方式组成的图是无向简单环图的子图,首先考虑n个点在一条链上,就是1,1,3....n!/2
可以发现这跟指数型母函数一样,于是考虑用指数型母函数用,选取m条边后,最多断开n-m条链,问题就转化为n个点组成n-m条链的方案数
然后对函数化简为: x^k*(1-x/2)^k*(1/(1-x)^k.
单独考虑每一项,最后我们只要x^n的系数
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; typedef long long ll; const int mod=1e9+7; const int maxn=1e6+5; ll inv2; ll A[maxn],FA[maxn]; ll qpow(ll a,ll b) { ll ans=1; while(b) { if(b&1) ans=ans*a%mod; a=a*a%mod; b>>=1; } return ans; } void init() { int i,j; A[0]=1; FA[0]=1; for(i=1; i<maxn; i++) A[i]=A[i-1]*i%mod; FA[1000001]=qpow(A[1000001],mod-2); for(i=1000000; i>=1; i--) { FA[i]=1LL*(i+1)*FA[i+1]%mod; } inv2=FA[2]; } ll getc(int n,int m) { if(m>n) return 0; return A[n]*FA[m]%mod*FA[n-m]%mod; } int main() { int i,j,k,n,m,t; ll temp,ans; init(); scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); if(m>n) { printf("0\n"); } else if(m==n) { printf("%lld\n",A[n-1]*inv2%mod); } else { ans=0; temp=1; k=n-m; for(i=0; i<=m; i++) { ans+=getc(k,i)*temp%mod*getc(k+(m-i)-1,m-i)%mod; ans%=mod; temp=(temp*-inv2%mod+mod)%mod; } printf("%lld\n",ans*A[n]%mod*FA[k]%mod); } } return 0; }