码迷,mamicode.com
首页 > 其他好文 > 详细

5.29 省选模拟赛 树形图求和 有向图矩阵树定理 高斯消元 行列式

时间:2020-05-29 21:25:09      阅读:63      评论:0      收藏:0      [点我收藏+]

标签:turn   复杂   cdn   题目   oid   修改   表示   code   stdin   

LINK:树形图求和

技术图片
技术图片

很妙的题目 因为之前没有了解过 有向图的矩阵树 所以自然GG了.

这里先给出矩阵树定理的三种形式 防止以后再考。

第一种 无向图的矩阵树 总所周知.

第二种 有向图的内向树 所谓内向树就是所有的点都指向一个点的有向树.

邻接矩阵矩阵 \(a_{i,j}\)表示i到j的路径条数 度数矩阵 \(a_{i,j}\)表示i的出度 拉普拉斯矩阵还是为度数矩阵-邻接矩阵 最后需要把根的那行那列去掉.

第三种 有向图的外向树 所谓外向树就是由某个点发出所有点都指向叶子节点.

邻接矩阵矩阵 \(a_{i,j}\)表示i到j的路径条数 度数矩阵 \(a_{i,j}\)表示i的入度 基尔霍夫矩阵还是为度数矩阵-邻接矩阵 最后需要把根的那行那列去掉.

对于20分 爆搜.复杂度C(30,9).

对于60分 如果把每条边看成多项式 不过这道题最后生成的多项式次数过大 插值是不能插出来的。

所以考虑每一条边的贡献 想办法求出某条边的方案数 容易想到总方案-不包含的很好算.

GAUSS消元求行列式 复杂度mn^3logn.

对于100分 有一个定理:当某一行或者某一列改变可以快速求出之后DET.

考虑某一行被修改成了 c1,c2,c3...

那么有 每一列有方程组\(\sum{a_{i,j}\cdot x_i}=c_j\)

求出\(x_i\)之后 将之前的DET乘上\(x_i\)即可得到当前矩阵的行列式.

不过这里\(c_j\)是动态变化的 考虑变成\(x_i=\sum_jb_j\cdot c_j\)的形式就可以快速求出\(x_i\)了。

这里列出方程后可以对右边列一个单位矩阵来高斯消元 这样就可以求出刚才那个形式了(也是矩阵求逆的过程.

最后求答案可以每次都扫一遍 当然还有更快的做法:简单推一下就知道了(见code.

值得注意的是 GAUSS的时候注意别漏了ll.

(感觉有点不太对劲 奈何实力有限 止步于此~

const int MAXN=310,G=3;
int n,m;
int a[MAXN][MAXN],f[MAXN][MAXN],I[MAXN][MAXN];
struct wy
{
	int x,y,z;
}t[100010];
inline void add(int x,int y)
{
	--a[x][y];++a[x][x];
}
inline int ksm(int b,int p)
{
	int cnt=1;
	while(p)
	{
		if(p&1)cnt=(ll)cnt*b%mod;
		b=(ll)b*b%mod;p=p>>1;
	}
	return cnt;
}
inline int DET(int n)
{
	int ans=1;
	rep(1,n,i)
	{
		rep(i+1,n,j)
		{
			while(a[j][i])
			{
				int d=a[i][i]/a[j][i];
				rep(i,n,k)a[i][k]=(a[i][k]-(ll)d*a[j][k])%mod;
				rep(1,n,k)swap(a[i][k],a[j][k]);
				ans=-ans;
			}
		}
		if(!a[i][i]){return 0;}
		ans=(ll)ans*a[i][i]%mod;
	}
	return (ans+mod)%mod;
}
inline void GAUSS(int n)
{
	rep(1,n,i)
	{
		int p=i;
		rep(i,n,j)if(f[j][i])p=j;
		if(p!=i)rep(1,n,j)swap(f[i][j],f[p][j]),swap(I[i][j],I[p][j]);
		int ww=ksm(f[i][i],mod-2);
		rep(1,n,j)
		{
			if(i==j)continue;
			int d=(ll)f[j][i]*ww%mod;
			rep(1,n,k)
			{
				f[j][k]=(f[j][k]-(ll)d*f[i][k]%mod+mod)%mod;
				I[j][k]=(I[j][k]-(ll)d*I[i][k]%mod+mod)%mod;
			}
		}
		rep(1,n,j)f[i][j]=(ll)f[i][j]*ww%mod,I[i][j]=(ll)I[i][j]*ww%mod;
	}
}
int main()
{
	freopen("calc.in","r",stdin);
    freopen("calc.out","w",stdout);
	get(n);get(m);
	rep(1,m,i)
	{
		int get(x),get(y),get(z);
		t[i]=(wy){x,y,z};
		add(x,y);
	}
	rep(1,n,i)
	{
		I[i][i]=1;
		rep(1,n,j)f[i][j]=a[j][i];
	}
	GAUSS(n);//解方程.
	int ans=DET(n-1);
	int sum=0;
	rep(1,m,i)
	{
		int x=t[i].x,y=t[i].y;
		if(x<n)
		{
			int ww=(I[x][x]-I[x][y]+mod)%mod;
			sum=(sum+(ll)ans*ww%mod*t[i].z)%mod;
		}
	}
	put(sum);return 0;
}

5.29 省选模拟赛 树形图求和 有向图矩阵树定理 高斯消元 行列式

标签:turn   复杂   cdn   题目   oid   修改   表示   code   stdin   

原文地址:https://www.cnblogs.com/chdy/p/12989268.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!