jzoj3085-图的计数【组合数,数论】

正题


题目大意

求有多少个m条边的有向图使得1到n的最短路长度为n-1


解题思路

首先长度为 n − 1 n-1 n1那么就是1到n得先是一条链。在链上加 m − n + 1 m-n+1 mn+1条边且不能加如捷径边。
捷径边的条数为 C n − 1 2 C_{n-1}^2 Cn12,然后可以加的边数就是 n ∗ n − C n − 1 2 n*n-C_{n-1}^2 nnCn12。但是考虑到有重边的情况,考虑用隔板法求。

n ∗ n − C n − 1 2 n*n-C_{n-1}^2 nnCn12物品放入 m − n + 1 m-n+1 mn+1个桶里,对于每张图就是加入桶里的第一条边,重边数量为桶中的物品数量。

然后因为 2 ∼ n − 1 2\sim n-1 2n1的点可以进行排列,所以答案要再乘上一个 ( n − 2 ) ! (n-2)! (n2)!

组合数用逆元求可过。


c o d e code code

#include
#define ll long long
using namespace std;
const ll XJQ=1e9+7;
ll n,m,j[10010],z;
ll power(ll x,ll b)
{
	ll ans=1;
	x%=XJQ;
	while(b){
		if(b&1) ans=ans*x%XJQ;
		x=x*x%XJQ;b>>=1;
	}
	return ans;
}
ll C(ll n,ll m)
{
	ll ans1=1,ans2=1;
	for(ll i=n-m+1;i<=n;i++)
	  ans2=ans2*i%XJQ;
	for(ll i=1;i<=m;i++)
	  ans1=ans1*power(i,XJQ-2)%XJQ;
	return ans2*ans1%XJQ;
}
int main()
{
	scanf("%lld%lld",&n,&m);
	j[0]=1;
	for(ll i=1;i<=n-2;i++)
	  j[i]=j[i-1]*i%XJQ;
	printf("%lld",C((n*n-C(n-1,2)-1+m-n+1),m-n+1)*j[n-2]%XJQ);
}

你可能感兴趣的:(数论and数学)