CSU 1805 Tree Capitals(Matrix-Tree定理+Best定理)

来源:互联网 发布:antlr sql解析 github 编辑:程序博客网 时间:2024/05/23 20:48

1805: Three Capitals

      Time Limit: 5 Sec     Memory Limit: 128 Mb     Submitted: 51     Solved: 32    


Description

In ICPCCamp, there are only three capitals -- Alpha, Beta andGamma. There are alsoa bidirectional roads between capitalsAlpha and Beta,b roads between Alpha and Gamma, and croads between Beta and Gamma.
Bobo lives in capital Alpha and would like to travel around ICPCCamp. He will start from capitalAlpha, travel along each road exactly once, and return back to capitalAlpha.
It is clear that Bobo has many plans to choose from. He would like to find out the number of different plans, modulo (109+7).
Note that two plans A and B are considered different only if there exists aniwhere the i-th traveled road in plan A is different from the i-th road in plan B.

Input

The input contains at most 30 sets. For each set:
The first line contains 3 integers a,b,c (1≤a,b,c≤105).

Output

 For each set, an integer denotes the number of different ways modulo (109+7).

Sample Input

1 1 31 3 1100000 100000 100000

Sample Output

1224525502296

Hint

Source

湖南省第十二届大学生计算机程序设计竞赛



        关于矩阵树定理,在暑假培训的时候hc学长略微提到过,没想到就是去年省赛的题目……

        所谓矩阵树定理,就是指一个图的生成树个数,等于基尔霍夫矩阵的任意n-1阶主子式的行列式的值。而基尔霍夫矩阵K又两个部分构成,一是图的邻接矩阵A,另一个是每个节点的度数矩阵B,如此基尔霍夫矩阵K=B-A。具体证明我就不给出了,自己去查吧,其实我也不知道……

        然后本题有点不同,这题是求欧拉回路的条数。其实差不多,对于欧拉回路的条数,我们有一个Best定理与Matrix-Tree定理类似,不同之处在于Best定理里面,度数矩阵B的度数是节点的入度,然后计算行列式的时候主子式是去掉起点所在行列的主子式,最后结果还要乘以每个节点入度减一的阶乘(起点不用减一)。

        知道了公式之后套就行了,但是还要注意,这题是无向图,所以我们还要枚举哪些边作为出边,哪些边作为入边。由于本题是一个三角形的环,所以只要枚举条边的出入情况就可以推出其他边的情况,所以时间复杂度上可以接受。我们假设枚举之后,a、b、c三条边的出边个数分别为x、y、z,那么最后结果还要乘上组合数C(a,x)*C(b,y)*C(c,z)。具体见代码:

#include<iostream>#include<cstdio>#include<cmath>#include<algorithm>#include<cstring>#define LL long long#define mod 1000000007using namespace std;LL fac[100010],x[3][3];int a,b,c;void init(){    fac[0]=1;    for(int i=1;i<=100005;i++)  fac[i]=fac[i-1]*i%mod;}LL qpow(LL a,LL n){    LL ans=1;    while(n)    {        if(n&1) ans=ans*a%mod;        a=a*a%mod;        n>>=1;    }    return ans;}LL C(LL n,LL m){    return fac[n]*qpow(fac[m]*fac[n-m]%mod,mod-2)%mod;}int main(){    init();    while(~scanf("%d%d%d",&a,&b,&c))    {        LL ans=0;        if((a+c)&1||(a+b)&1||(b+c)&1) {puts("0");continue;}        for(int i=0;i<=a;i++)        {            memset(x,0,sizeof(x));            x[0][0]=(a+b)/2; x[1][1]=(a+c)/2; x[2][2]=(b+c)/2;            x[0][1]=-i; x[1][0]=-(a-i); x[0][2]=-(x[0][0]-i);            x[2][0]=-(b+x[0][2]); x[1][2]=-(x[1][1]+x[1][0]); x[2][1]=-(x[2][2]+x[2][0]);            if (x[2][0]>0||x[1][2]>0||x[0][2]>0||x[2][1]>0) continue;            LL res=(C(a,-x[0][1])*C(b,-x[0][2])%mod)*C(c,-x[1][2])%mod;            res=res*fac[x[1][1]-1]%mod*fac[x[2][2]-1]%mod*fac[x[0][0]]%mod;            res=res*((x[1][1]*x[2][2]%mod-x[1][2]*x[2][1]%mod+mod)%mod)%mod;//计算行列式            ans+=res;        }        printf("%lld\n",ans%mod);    }}

阅读全文
0 0
原创粉丝点击