洛谷4455 [CQOI2018]社交网络 (有向图矩阵树定理)(学习笔记)

sro_ptx_orz

qwq算是一个套路的记录

对于一个有向图来说

如果你要求一个外向生成树的话,那么如果存在一个 u r u\rightarrow r 的边
那么 a [ u ] [ v ] , a [ v ] [ v ] + + a[u][v]--,a[v][v]++

对应的去掉第 i i 行和第 i i 列的余子式,就是以 i i 为根的生成树个数。

内向生成树也是同理。所有的反过来即可

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk make_pair
#define ll long long
//#define int long long
#define rint register int
using namespace std;
inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}
const int maxn = 310; 
const int mod = 10007;
int qsm(int i,int j)
{
	int ans=1;
	while (j)
	{
		if (j&1) ans=ans*i%mod;
		i=i*i%mod;
		j>>=1;
	}
	return ans;
}
int a[maxn][maxn];
int n,m;
int d[maxn][maxn];
int b[maxn][maxn];
void gauss()
{
	int k=1;
	int ff=1;
	int ans=1;
	for (rint i=1;i<=n;++i)
	{
		int now = k;
		while (now<=n && !(a[now][i])) ++now;
		if (now==n+1) continue;
		if (now!=k) ff*=-1;
		for (rint j=1;j<=n;++j) swap(a[now][j],a[k][j]);
		int inv = qsm(a[k][i],mod-2);
        for (rint j=i+1;j<=n;++j)
		{
			int t = a[j][i]*inv%mod;
			for (rint p=1;p<=n;++p) a[j][p]=(a[j][p]-a[k][p]*t%mod+mod)%mod;
		}
		++k;
	}
	for (rint i=1;i<=n;++i) ans=ans*a[i][i]%mod;
	if(ff==-1) cout<<mod-ans;
	else cout<<ans;
}
signed main()
{
  n=read(),m=read();
  for (rint i=1;i<=m;++i)
  {
  	int x=read(),y=read();
  	a[x][x]++;
  	a[y][x]--;
  }
  for (rint i=1;i<=n;++i)
    for (rint j=1;j<=n;++j) b[i][j]=a[i][j];
  for (rint i=1;i<n;++i)
    for (rint j=1;j<n;++j)
    {
    	a[i][j]=b[i+1][j+1];
	}
  n--;
  gauss(); 
  return 0;
}

猜你喜欢

转载自blog.csdn.net/y752742355/article/details/85335337