ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[模板] BEST 定理

2022-03-08 21:34:50  阅读:191  来源: 互联网

标签:const int 定理 模板 include BEST 欧拉 出边


一、题目

点此看题

二、解法

这篇博客主要记录我的感性理解,相信能帮助你直观地理解 \(\tt BEST\) 定理。

首先对于一条欧拉路径,我们考虑保留每个点的最后一条出边。可以证明出边一定构成一棵内向树,我们只需要证明不会构成环,而如果构成环,考虑走完环的最后一条出边一定会停留在这个点,那么就无法停留在出发点了,这与欧拉路径是矛盾的。

所以我们考虑统计出内向树的个数,那么剩下的边怎么排列呢?发现任意排列都可以构成欧拉路径,所以要乘上 \(\prod_{i=1}^n(deg(i)-1)!\),那么我们就得到了 \(\tt BEST\) 定理,设 \(T\) 为内向生成树个数:

\[T\cdot \prod_{i=1}^n(deg(i)-1)! \]

本题起点第一条边的选择也是需要考虑的,所以还要在此基础上乘上 \(deg(1)\)

使用此定理的条件是存在欧拉路径,我们需要判断每个点入度\(=\)出度,以及所有的边弱联通。计算行列式的时候对于没有边的点需要忽略(要不然就把 \(0\) 乘进去了)

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 105;
const int M = 200005;
const int MOD = 1e6+3;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int T,n,fac[M],in[N],out[N],fa[N],a[N][N];
int find(int x)
{
	if(fa[x]!=x) fa[x]=find(fa[x]);
	return fa[x];
}
int qkpow(int a,int b)
{
	int r=1;
	while(b>0)
	{
		if(b&1) r=r*a%MOD;
		a=a*a%MOD;
		b>>=1;
	}
	return r;
}
int gauss()
{
	int ans=1;
	for(int i=2;i<=n;i++)
	{
		for(int j=i;j<=n;j++)
			if(!a[i][i] && a[j][i])
			{
				swap(a[i],a[j]);
				ans=MOD-ans;
				break;
			}
		if(out[i]) ans=ans*a[i][i]%MOD;
		for(int j=1;j<=n;j++)
		{
			if(i==j || !a[j][i]) continue;
			int t=a[j][i]*qkpow(a[i][i],MOD-2)%MOD;
			for(int k=1;k<=n;k++)
				a[j][k]=(a[j][k]-t*a[i][k]%MOD+MOD)%MOD;
		}
	}
	return ans;
}
void work()
{
	n=read();int fl=1;
	memset(a,0,sizeof a);
	for(int i=1;i<=n;i++)
		fa[i]=i,in[i]=out[i]=0;
	for(int i=1;i<=n;i++)
	{
		int k=read();
		while(k--)
		{
			int j=read();out[i]++;in[j]++;
			a[j][j]=(a[j][j]+1)%MOD;
			a[i][j]=(a[i][j]+MOD-1)%MOD;
			fa[find(i)]=find(j);
		}
	}
	for(int i=1;i<=n;i++)
		if(in[i]!=out[i] || (out[i] && find(i)^find(1)))
			{puts("0");return ;}
	for(int i=1;i<=n;i++) fl&=(out[i]==0);
	if(fl) {puts("1");return ;}
	int ans=gauss()*out[1]%MOD;
	for(int i=1;i<=n;i++)
		if(out[i]) ans=ans*fac[out[i]-1]%MOD;
	printf("%lld\n",ans);
}
signed main()
{
	T=read();fac[0]=1;
	for(int i=1;i<=200000;i++)
		fac[i]=fac[i-1]*i%MOD;
	while(T--) work();
}

标签:const,int,定理,模板,include,BEST,欧拉,出边
来源: https://www.cnblogs.com/C202044zxy/p/15982580.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有