[组合数学]JZOJ 3085 图的计数

Description

在观察完第一个作业之后你终于开始观察第二个作业了,第二个作业十分无聊,就只是一道题目。


询问有多少个N个点,M条边的有向图,从1号点到达N号点需要经过至少N-1条边。该有向图中可以包含重边和自环。


 

 

Input

第一行两个整数N,M


 

Output

仅一个整数表示答案 mod (10^9+7)。


 

 

Sample Input

2 2

Sample Output

4
 

Data Constraint

 
 

Hint

对于30%的数据 N<=5,M<=10


对于60%的数据 N<=80,M<=3000


对于100%的数据 1<=N<=10000  1<=M<=100000

分析

首先我们确定n-1条边构成的一定是链(废话)

然后我们显然要乘上点的全排列(n-2)!

那么剩下m-n+1条边显然不能成为捷径边(就是使最短路变短的边)

这种捷径边共有(n-1)*(n-2)/2个,之所以要除二是因为反向边不算

然后剩下的就是十分经典的隔板法

答案=C(m-n+1,n*n-(n-1)*(n-2)/2+m-n+1-1)*(n-2)!

 

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N=1e4+10;
const int M=1e5+10;
const ll P=1e9+7;
ll n,m;

ll Power(ll a,ll b) {ll ans=1;for (;b;b>>=1,(a*=a)%=P) if (b&1) (ans*=a)%=P;return ans;}

ll Fact(ll a,ll from) {
    ll ans=1ll;
    for (ll i=from;i<=a;i++) (ans*=i)%=P;
    return ans;
}

int main() {
    scanf("%lld%lld",&n,&m);
    ll C1=(n-1ll)*(n-2ll)%P*Power(2ll,P-2ll)%P;
    ll C=Fact(n*n-C1+m-n,n*n-C1)*Power(Fact(m-n+1ll,1),P-2ll)%P;
    printf("%lld",C*Fact(n-2ll,1)%P);
}
View Code

 

posted @ 2019-01-24 20:53  Vagari  阅读(185)  评论(0编辑  收藏  举报