jzoj3085. 图的计数

Description

在观察完第一个作业之后你终于开始观察第二个作业了,第二个作业十分无聊,就只是一道题目。
询问有多少个N个点,M条边的有向图,从1号点到达N号点需要经过至少N-1条边。该有向图中可以包含重边和自环。

Input

第一行两个整数N,M。

Output

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

Sample Input

2 2

Sample Output

4

Data Constraint

对于30%的数据 N<=5,M<=10
对于60%的数据 N<=80,M<=3000
对于100%的数据 1<=N<=10000 1<=M<=100000

题解

这题我们看到要求——有向图,n-1条边,可重边+可自环
想到一个可行的方案必定是满足以下几个条件——
1.是一条链且开头为1,结尾为n,中间的是可以打乱顺序的。
2.多出来的边必定是反向边或自环或正向边且距离不超过1。
依照这两个条件我们可以知道
第一个条件贡献的答案为(n2)!(n-2)!
第二个条件下,每条多出来的边的连接方案为——
n+(n1)+n(n1)/2n+(n-1)+n*(n-1)/2
分别表示该边连接自环、该边正向连接两个点、该边反向连接任意两个点。
这样我们就可以算答案了。
但是要注意,由于每个边的连接方法是等价的,所以第二个条件下的贡献要用组合数来算。
我们把每条多出来的边看做是球,每种连接方案看做是箱子。
于是问题就转化成了给你n个相同球,放入m个不同的箱子里,允许空盒的方案。
这就是一个挡板问题,求解即可。
注意常数!!!

代码

{$inline on}
var
        i,j,k,l,n,m:longint;
        p,q,answer,x1,x2,x3:int64;
        //jc:array[-1..10001] of int64;
        mo:int64=1000000007;
function qsm(a,b:int64):int64;inline;
var
        t,y:int64;
begin
        t:=1;
        y:=a;
        while b<>0 do
        begin
                if(b and 1)=1 then
                        t:=(t*y) mod mo;
                y:=(y*y) mod mo;
                b:=b shr 1;
        end;
        exit(t);
end;
begin
        readln(n,m);
        answer:=1;
        for i:=2 to n-2 do
        begin
                answer:=answer*i mod mo;
        end;
        q:=n;
        p:=q*(q-1) div 2+q+(q-1);//hezi
        m:=m-n+1;
        x1:=1;
        x2:=1;
        x3:=1;
        for i:=1 to m+p-1 do
        begin
                if i<=m then x1:=x1*i mod mo;
                if i<=p-1 then x2:=x2*i mod mo;
                x3:=x3*i mod mo;
        end;
        answer:=answer*qsm(x1*x2 mod mo,mo-2) mod mo*x3 mod mo;
        writeln(answer);
end.
end.

posted @ 2019-01-23 15:49  RainbowCrown  阅读(187)  评论(0编辑  收藏  举报