所有生成树边权和的和的求法

Posted lnzwz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了所有生成树边权和的和的求法相关的知识,希望对你有一定的参考价值。

通常,矩阵树定理算出的生成树是边权乘积的和。
如果计算所有生成树边权和的和,比较暴力的方法就是枚举一条边,然后计算包含这条边的生成树个数。

这样的时间复杂度是(O(mn^3))的,最坏为(O(n^3))
考虑优化:

对于一条边权为w的边,将边权设为关于x的多项式(1+wx)
这样,容易证出,最后的一次项系数就是答案。

把多项式代入高斯消元求值即可。
计算时保留两项即可。

((a+bx)*(c+dx)=ac+(ad+bc)x)
(frac{1}{a+bx}=frac{1}{a}-frac{bx}{a^2})

代码:

struct SJd
{
	int a,b;
	SJd(){}
	SJd(int A,int B)
	{
		a=A;b=B;
	}
	SJd(int X)
	{
		a=1;b=X;
	}
};
SJd operator+(SJd x,SJd y)
{
	return SJd((x.a+y.a)%md,(x.b+y.b)%md);
}
SJd operator-(SJd x,SJd y)
{
	return SJd((x.a-y.a+md)%md,(x.b-y.b+md)%md);
}
SJd operator*(SJd x,SJd y)
{
	return SJd(1ll*x.a*y.a%md,(1ll*x.a*y.b+1ll*x.b*y.a)%md);
}
SJd niy(SJd x)
{
	int ny=ksm(x.a,md-2);
	return SJd(ny,(md-1ll*x.b*ny%md*ny%md)%md);
}
int gauss(SJd sz[31][31],int n)
{
	SJd ans(1,0);
	for(int i=0;i<n;i++)
	{
		int wz=-1;
		for(int j=i;j<n;j++)
		{
			if(sz[j][i].a)
			{
				wz=j;
				break;
			}
		}
		if(wz==-1)continue;
		if(wz!=i)
		{
			ans.a=md-ans.a;
			for(int j=i;j<n;j++)
			{
				SJd t=sz[wz][j];
				sz[wz][j]=sz[i][j];
				sz[i][j]=t;
			}
		}
		SJd z=niy(sz[i][i]);
		for(int j=i+1;j<n;j++)
		{
			SJd t=sz[j][i]*z;
			for(re int k=i;k<n;k++)
				sz[j][k]=sz[j][k]-sz[i][k]*t;
		}
	}
	for(int i=0;i<n;i++)
		ans=ans*sz[i][i];
	return ans.b;
}
int A[500],B[500],C[500];SJd sz[31][31];
void addb(int a,int b,int c)
{
	sz[a][a]=sz[a][a]+c;
	sz[a][b]=sz[a][b]-c;
}
//......





以上是关于所有生成树边权和的和的求法的主要内容,如果未能解决你的问题,请参考以下文章

数列前n项和都有哪些求法?

bzoj4033

求自然数列中前n 个数的和。

BZOJ 1937: [Shoi2004]Mst 最小生成树 [二分图最大权匹配]

严格最小生成树

[HAOI2015]树上染色