这个Best定理的名字似乎是四个人的姓的首字母拼起来的
我还以为是最好的定理的意思
前置技能:矩阵树定理(Matrix-tree)
无向图的生成树个数即基尔霍夫矩阵的行列式
有向图的生成树有两种:外向的和内向的
外向树即所有边从根节点指出去
内向树即所有边指向根节点
外向生成树的基尔霍夫矩阵为入度矩阵-度数矩阵
内向生成树的基尔霍夫矩阵为出度矩阵-度数矩阵
有向生成树个数为其基尔霍夫矩阵除了根节点的那行的主子式之和
Best定理:一个点出发的欧拉回路个数为
即以这个点为根的外向生成树个数乘上每个点的度数-1的阶乘(其实以任意点为根都行)
证明感性理解下吧我不会qwq
然后如果经过的边的序列不同算不同的方案的话还要乘上一个根节点的度数
Code:
#include<bits/stdc++.h>
#define mod 1000003
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
inline int add(int x,int y){x+=y;if(x>=mod) x-=mod;return x;}
inline int dec(int x,int y){x-=y;if(x<0) x+=mod;return x;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline void inc(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline void Dec(int &x,int y){x-=y;if(x<0) x+=mod;}
inline void Mul(int &x,int y){x=1ll*x*y%mod;}
inline int ksm(int a,int b){int res=1;for(;b;b>>=1,a=mul(a,a)) if(b&1) res=mul(res,a);return res;}
const int N=105,M=2e5+5;
int e[N][N],a[N][N];
int fac[M],ifac[M];
inline void init(int n){
fac[0]=ifac[0]=1;
for(int i=1;i<=n;i++) fac[i]=mul(fac[i-1],i);
ifac[n]=ksm(fac[n],mod-2);
for(int i=n-1;i;i--) ifac[i]=mul(ifac[i+1],i+1);
}
inline int det(int n){
int ans=1;
for(int i=1;i<=n;i++){
int pos;for(pos=i;pos<=n;pos++) if(a[pos][i]) break;
if(pos==n+1) return 0;
if(pos!=i){swap(a[i],a[pos]);ans=dec(0,ans);}
Mul(ans,a[i][i]);
int iv=ksm(a[i][i],mod-2);
for(int j=i;j<=n;j++) Mul(a[i][j],iv);
for(int j=i+1;j<=n;j++) if(a[j][i]){
iv=a[j][i];
for(int k=i;k<=n;k++) Dec(a[j][k],mul(iv,a[i][k]));
}
}
return ans;
}
int ou[N];
int main(){
init(200000);
while(1){
memset(a,0,sizeof(a));
int n=read();
if(n==0) return 0;
for(int i=1;i<=n;i++){
int k=read();ou[i]=k;
for(int j=1;j<=k;j++){
int x=read();
if(x^i) --a[i][x],++a[i][i];
}
}
if(n==1){cout<<fac[ou[1]]<<"\n";continue;}
int ans=det(n-1);
for(int i=1;i<=n;i++) Mul(ans,fac[ou[i]-1]);
cout<<mul(ans,ou[1])<<"\n";
}
}