题目
解法一
首先对于树形图的个数这样算:
a[i][i]表示i号点的出度,a[i][j]表示从i到j的边个数的相反数
去掉第n行第n列后剩下的矩阵的行列式即为树形图个数
考虑枚举每条边并计算这条边的影响。
就是说我们枚举一条边(x,y)然后a[x][x]–,a[x][y]++重新计算行列式
对于如下矩阵:
A=⎡⎣⎢⎢a1,1⋮an,1⋯⋱⋯a1,n⋮an,n⎤⎦⎥⎥
若我们将第k列改成c[]
即
B=⎡⎣⎢⎢a1,1⋮an,1⋯⋱⋯a1,k−1⋮an,k−1c1⋮cna1,k+1⋮an,k+1⋯⋱⋯a1,n⋮an,n⎤⎦⎥⎥
考虑如下方程:
对于所有i有:∑j=1nai,j⋅xj=ci
那么有:
det(B)=det(A)×xk
上述方程中x为未知数, xi 的意义为:把某一列的数加到第k列得到c的系数。
我们可以用c表示出所有的x,当我们需要查询的时候就直接扫一下代入就好了
解法二
而我的解法是这样的:
定义二元组(a,b)表示方案数为a,每种方案的权值和为b。
那么乘法相当于两个二元组的组合,即:
(a,b)×(c,d)=(ac,ad+bc)
相应的也可以推出除法(虽然并没有什么组合意义),加法,减法
而其零元为:(0,0)
其单位元为:(1,0)
然后就可以直接代入进去做高斯消元了
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<set>
#include<bitset>
#include<map>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long LL;
typedef double db;
int get(){
char ch;
while(ch=getchar(),(ch<'0'||ch>'9')&&ch!='-');
if (ch=='-'){
int s=0;
while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0';
return -s;
}
int s=ch-'0';
while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0';
return s;
}
const int N = 310;
const int mo = 1E+9+7;
LL add(LL x,LL y){return x+y>=mo?x+y-mo:x+y;}
LL quickmi(LL x,LL tim){
LL ans=1;
for(;tim;tim/=2,x=x*x%mo)
if (tim%2)ans=ans*x%mo;
return ans;
}
struct numb{
LL a,b;
numb(const int a_=0,const int b_=0){a=a_;b=b_;}
};
numb operator *(numb a,numb b){return numb(a.a*b.a%mo,add(a.a*b.b%mo,a.b*b.a%mo));}
numb operator +(numb a,numb b){return numb(add(a.a,b.a),add(a.b,b.b));}
numb operator -(numb a,numb b){return numb((a.a+mo-b.a)%mo,(a.b+mo-b.b)%mo);}
numb operator /(numb a,numb b){
LL tmp=quickmi(b.a,mo-2);
LL a_=a.a*tmp%mo;
return numb(a_,((a.b+mo-a_*b.b%mo)%mo)*tmp%mo);
}
numb operator *(numb a,LL x){return numb(a.a*x%mo,a.b*x%mo);}
numb operator /(numb a,LL x){
LL tmp=quickmi(x,mo-2);
return numb(a.a*tmp%mo,a.b*tmp%mo);
}
struct matrix{
numb a[N][N];
numb* operator [](int x){return a[x];}
}a;
int n,m;
numb d[N];
int fa[N];
numb ny[N];
int getfather(int x){
if (fa[x]==x)return x;
return fa[x]=getfather(fa[x]);
}
int main(){
freopen("calc.in","r",stdin);
freopen("calc.out","w",stdout);
n=get();m=get();
fo(i,1,n)fa[i]=i;
fo(i,1,m){
int x=get(),y=get(),v=get();
int tx=getfather(x),ty=getfather(y);
fa[tx]=ty;
numb u=numb(1,v);
a[x][y]=a[x][y]+u;
//a[y][x]=a[y][x]+u;
d[x]=d[x]+u;
//d[y]=d[y]+u;
}
bool bz=1;
int lst=getfather(1);
fo(i,2,n){
int u=getfather(i);
if (u!=lst){bz=0;break;}
}
if (!bz){
printf("0\n");
fclose(stdin);
fclose(stdout);
}
fo(x,1,n)
fo(y,1,n)
a[x][y]=a[x][y]*(mo-1);
fo(x,1,n)a[x][x]=d[x];
n--;
fo(i,1,n){
fo(j,1,i-1)
if (a[i][j].a||a[i][j].b){
numb tmp=a[i][j]*ny[j];
fo(x,1,n)a[i][x]=a[i][x]-tmp*a[j][x];
}
ny[i]=numb(1,0)/a[i][i];
}
numb ans=numb(1,0);
fo(i,1,n)ans=ans*a[i][i];
printf("%lld\n",ans.b);
fclose(stdin);
fclose(stdout);
return 0;
}