洛谷 P2144 [FJOI2007]轮状病毒

题意简述

求一种特殊无向图的生成树个数
无向图如图:

题解思路

用Matrix-Tree定理,求出基尔霍夫矩阵来计算,再递推答案;
(Ans(x)=3 imes Ans(x-1)-Ans(x-2)+2)

证明:

我们令轮状病毒圆心编号为1,圆环上点编号从2~n+1
则可以得出无向图的度数矩阵D和邻接矩阵E
(D=egin{bmatrix}n&0&0&0&0&cdots&0&0&0&0\0&3&0&0&0&cdots&0&0&0&0\0&0&3&0&0&cdots&0&0&0&0\0&0&0&3&0&cdots&0&0&0&0\0&0&0&0&3&cdots&0&0&0&0\vdots&vdots&vdots&vdots&vdots&ddots&vdots&vdots&vdots&vdots\0&0&0&0&0&cdots&3&0&0&0\0&0&0&0&0&cdots&0&3&0&0\0&0&0&0&0&cdots&0&0&3&0\0&0&0&0&0&cdots&0&0&0&3\end{bmatrix})
(E=egin{bmatrix}0&1&1&1&1&cdots&1&1&1&1\1&0&1&0&0&cdots&0&0&0&1\1&1&0&1&0&cdots&0&0&0&0\1&0&1&0&1&cdots&0&0&0&0\1&0&0&1&0&cdots&0&0&0&0\vdots&vdots&vdots&vdots&vdots&ddots&vdots&vdots&vdots&vdots\1&0&0&0&0&cdots&0&1&0&0\1&0&0&0&0&cdots&1&0&1&0\1&0&0&0&0&cdots&0&1&0&1\1&1&0&0&0&cdots&0&0&1&0\end{bmatrix})
再得到
基尔霍夫Kirchhoff矩阵 (K=egin{bmatrix}n&-1&-1&-1&-1&cdots&-1&-1&-1&-1\-1&3&-1&0&0&cdots&0&0&0&-1\-1&-1&3&-1&0&cdots&0&0&0&0\-1&0&-1&3&-1&cdots&0&0&0&0\-1&0&0&-1&3&cdots&0&0&0&0\vdots&vdots&vdots&vdots&vdots&ddots&vdots&vdots&vdots&vdots\-1&0&0&0&0&cdots&3&-1&0&0\-1&0&0&0&0&cdots&-1&3&-1&0\-1&0&0&0&0&cdots&0&-1&3&-1\-1&-1&0&0&0&cdots&0&0&-1&3\end{bmatrix})
然后我们要求K的代数余子式的值,显然是将带有n的那一行,那一列(即第一行,第一列)去掉
接下来就是求n阶行列式(A=egin{vmatrix}3&-1&0&0&cdots&0&0&0&-1\-1&3&-1&0&cdots&0&0&0&0\0&-1&3&-1&cdots&0&0&0&0\0&0&-1&3&cdots&0&0&0&0\vdots&vdots&vdots&vdots&ddots&vdots&vdots&vdots&vdots\0&0&0&0&cdots&3&-1&0&0\0&0&0&0&cdots&-1&3&-1&0\0&0&0&0&cdots&0&-1&3&-1\-1&0&0&0&cdots&0&0&-1&3\end{vmatrix})
对于A,显然不能用(n^3)的高斯消元,所以我们要探究A的性质。
将A的第一行变换到最后一行,得到(B=egin{vmatrix}-1&3&-1&0&cdots&0&0&0&0\0&-1&3&-1&cdots&0&0&0&0\0&0&-1&3&cdots&0&0&0&0\0&0&0&-1&cdots&0&0&0&0\vdots&vdots&vdots&vdots&ddots&vdots&vdots&vdots&vdots\0&0&0&0&cdots&-1&3&-1&0\0&0&0&0&cdots&0&-1&3&-1\-1&0&0&0&cdots&0&0&-1&3\3&-1&0&0&cdots&0&0&0&-1\end{vmatrix})
先根据行列式的性质得到(A=(-1)^{n-1} imes B)
我们发现除了左下角有三个数字外,B已经是一个上三角行列式,接下来是要消去左下角的三个数字
先消第n-1行(倒数第二行)
假设现在在消第i位,设(F_i)表示这一行的第i个数,(G_i)表示这一行第i+1个数
那么我们可以将B的第i行( imes F_i)加到这一来,就可消去第i位。因为第i行-1后面一定是3,所以第i+1位(+3 imes F_i)同理,第i+2位(+(-F_i))

(egin{cases}F_{i+1}=G_i+3 imes F_i\G_{i+1}=-F_i\end{cases})
由第二个式子推出(G_i=-F_{i-1})带人第一个式子中,得到(F_{i+1}=3 imes F_i-F_{i-1}),同时也可得到(G_{i+1}=3 imes G_i-G_{i-1})
然后可以快速地将第n-1行消成(egin{bmatrix}0&0&0&0&cdots&0&0&F_{n-1}-1&G_{n-1}+3end{bmatrix})
同样的方法,我们可以来消第n行
设第i位为(H_i),第i+1位为(L_i)
可得方程
(egin{cases}H_{i+1}=L_i+3 imes H_i\L_{i+1}=-H_i\end{cases})
解得(H_{i+1}=3 imes H_i-H_{i-1}qquad L_{i+1}=3 imes L_i-L_{i-1})
将第n行消成(egin{bmatrix}0&0&0&0&cdots&0&0&H_{n-1}&L_{n-1}-1end{bmatrix})
(F_{n-1}-1=fqquad G_{n-1}+3=gqquad H_{n-1}=hqquad L_{n-1}-1=l;)
(B=egin{vmatrix}-1&3&-1&0&cdots&0&0&0&0\0&-1&3&-1&cdots&0&0&0&0\0&0&-1&3&cdots&0&0&0&0\0&0&0&-1&cdots&0&0&0&0\vdots&vdots&vdots&vdots&ddots&vdots&vdots&vdots&vdots\0&0&0&0&cdots&-1&3&-1&0\0&0&0&0&cdots&0&-1&3&-1\0&0&0&0&cdots&0&0&f&g\0&0&0&0&cdots&0&0&h&l\end{vmatrix})=((-1)^{n-2} imes egin{vmatrix}f&g\h&l\end{vmatrix})
所以(A=(-1)^{n-1} imes B=(-1)^{2n-3} imes egin{vmatrix}f&g\h&l\end{vmatrix}=-f imes l+g imes h)
再推一推F,G,H,L,可以看出
(H_{i-1}=L_{i}=F_{i}=G_{i+1})
最后就可以推出(Ans(n)=3 imes Ans(n-1)-Ans(n-2)+2)
如果推不出,也可以求出(F_{i-1},F_{i},F_{i+1})再来求答案

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
int n;
struct Number {
	int len;
	int num[1000];
	Number() {
		len=0;
		memset(num,0,sizeof(num));
	}
	void operator =(const Number x) {
		len=x.len;
		for (register int i=1;i<=len;++i) num[i]=x.num[i];
	}
	void operator +=(const Number x) {
		len=std::max(len,x.len);
		for (register int i=1;i<=len;++i) {
			num[i]=num[i]+x.num[i];
			if (num[i]>=10) num[i]-=10,++num[i+1];
		}
		if (num[len+1]) ++len;
	}
	void operator -=(const Number x) {
		int xx=std::min(len,x.len);
		for (register int i=1;i<=xx;++i) {
			num[i]=num[i]-x.num[i];
			if (num[i]<0) num[i]+=10,--num[i+1];
		}
		while (!num[len]) --len;
	}
	Number operator *(const int& x) {
		Number res;
		for (register int i=1;i<=len;++i) {
			res.num[i]+=num[i]*3;
			res.num[i+1]+=res.num[i]/10;
			res.num[i]=res.num[i]%10;
		}
		res.len=len;
		if (res.num[len+1]) ++res.len;
		return res;
	}
	void print() {
		for (register int i=len;i;--i) printf("%d",num[i]);
		puts("");
	}
} x,y,z,_2;
int main() {
	scanf("%d",&n);
	if (n==1) puts("1");
	else if (n==2) puts("5");
	else {
		_2.len=1; _2.num[1]=2;
		x.len=x.num[1]=1;
		y.len=1; y.num[1]=5;
		for (register int i=3;i<=n;++i) {
			z=y*3; z-=x; z+=_2;
			x=y; y=z;
		}
		z.print();
	}
} 
原文地址:https://www.cnblogs.com/xuyixuan/p/11317006.html