把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【BZOJ3659】Which Dreamed It(BEST定理)

点此看题面

大致题意: 求有向图欧拉回路个数。

\(BEST\)定理

有向图欧拉回路个数为:

\[Tree(x)\times \sum_{i=1}^n(deg_i-1)! \]

其中\(Tree(x)\)为以\(x\)为根的外向树个数,\(deg_i\)为每个点的入度。

\(Tree(x)\)可以用矩阵树定理求出,具体可见此题:【BZOJ4894】天赋(外向树的矩阵树定理)

至于这个的意义,大致就是在确定一棵生成树的基础上,枚举每条边走的顺序,必然对应了一种方案。

不过由于此题中起点从不同边出发有不同走法,而这些走法会被视为同一种欧拉回路,因此还需要将答案乘上\(deg_1\)

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100
#define S 200000
#define X 1000003
#define Inc(x) (++x==X&&(x=0))
#define Dec(x) (!x--&&(x=X-1))
using namespace std;
int n,Fac[S+5],d[N+5],op,a[N+5][N+5];
I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
I void Find(CI x)
{
	if(a[x][x]) return;RI i;for(i=x+1;i<=n&&!a[i][x];++i);
	for(RI j=x;j<=n;++j) swap(a[x][j],a[i][j]);op=X-op;
}
int main()
{
	RI i,j,k;for(Fac[0]=i=1;i<=S;++i) Fac[i]=1LL*Fac[i-1]*i%X;//预处理阶乘
	RI Tt,x,t;W(scanf("%d",&n),n)
	{
		for(i=1;i<=n;++i) for(j=1;j<=n;++j) a[i][j]=0;//清空
		for(i=1;i<=n;++i) for(scanf("%d",&d[i]),j=1;j<=d[i];++j) scanf("%d",&x),Inc(a[x][x]),Dec(a[i][x]);//入度矩阵-邻接矩阵
		if(n==1) {printf("%d\n",Fac[d[1]]);continue;}//特判n=1
		for(op=1,i=2;i<=n;++i) for(Find(i),j=i+1;j<=n;++j)//高斯消元求行列式
			for(t=X-1LL*a[j][i]*QP(a[i][i],X-2)%X,k=i;k<=n;++k) a[j][k]=(1LL*t*a[i][k]+a[j][k])%X;
		for(t=op,i=2;i<=n;++i) t=1LL*t*a[i][i]%X;for(i=1;i<=n;++i) t=1LL*t*Fac[d[i]-1]%X;//BEST定理
		printf("%d\n",1LL*t*d[1]%X);//最后乘上deg[1]
	}return 0;
}
posted @ 2020-06-10 19:10  TheLostWeak  阅读(223)  评论(0编辑  收藏  举报