青岛金牌题补题

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

 

posted @ 2018-11-17 19:47  电竞毒奶  阅读(141)  评论(0编辑  收藏  举报