1. 程式人生 > >青島金牌題補題

青島金牌題補題

   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; }