循环矩阵及其应用

循环矩阵及其应用


引入

在信息学竞赛中,矩阵是一个非常常用的知识点,而其中矩阵乘法的时间复杂度为 \(O(n^3)\)。但是其中一些矩阵拥有特殊的构造,使得它能够更快的求解,例如我们今天需要了解的循环矩阵,它的求解复杂度可以优化到 \(O(n^2)\) 甚至 \(O(n\log_2{n})\)(但是我不会)。


分析

设循环矩阵 \(A\),它的内部排列大概是这样的:

\[A = \begin{bmatrix} a_{1,1} & \cdots & a_{1,n-1} & a_{1,n} \\ \vdots & \ddots & \vdots & \vdots \\ a_{n-1,1} & \cdots & a_{n-1,n-1} & a_{n-1,n} \\ a_{n,1} & \cdots & a_{n,n-1} & a_{n,n} \\ \end{bmatrix} = \begin{bmatrix} b_{1} & \cdots & b_{3} & b_{2} \\ \vdots & \ddots & \vdots & \vdots \\ b_{n-1} & \cdots & b_{1} & b_{n} \\ b_{n} & \cdots & b_{2} & b_{1} \\ \end{bmatrix}\\ \]

我们通过普通的矩阵乘法可以把它计算出来:

\[\begin{aligned} A' = A \times A & = \begin{bmatrix} a_{1,1} & \cdots & a_{1,n-1} & a_{1,n} \\ \vdots & \ddots & \vdots & \vdots \\ a_{n-1,1} & \cdots & a_{n-1,n-1} & a_{n-1,n} \\ a_{n,1} & \cdots & a_{n,n-1} & a_{n,n} \\ \end{bmatrix} \begin{bmatrix} a_{1,1} & \cdots & a_{1,n-1} & a_{1,n} \\ \vdots & \ddots & \vdots & \vdots \\ a_{n-1,1} & \cdots & a_{n-1,n-1} & a_{n-1,n} \\ a_{n,1} & \cdots & a_{n,n-1} & a_{n,n} \\ \end{bmatrix}\\ & = \begin{bmatrix} b_{1} & \cdots & b_{3} & b_{2} \\ \vdots & \ddots & \vdots & \vdots \\ b_{n-1} & \cdots & b_{1} & b_{n} \\ b_{n} & \cdots & b_{2} & b_{1} \\ \end{bmatrix} \begin{bmatrix} b_{1} & \cdots & b_{3} & b_{2} \\ \vdots & \ddots & \vdots & \vdots \\ b_{n-1} & \cdots & b_{1} & b_{n} \\ b_{n} & \cdots & b_{2} & b_{1} \\ \end{bmatrix}\\ &= \begin{bmatrix} \sum_{(i+j-2)\pmod n + 1 = 1} b_i \times b_j & \cdots & \sum_{(i+j-2)\pmod n + 1 = 2} b_i \times b_j \\ \vdots & \ddots & \vdots \\ \sum_{(i+j-2)\pmod n + 1 = n} b_i \times b_j & \cdots & \sum_{(i+j-2)\pmod n + 1 = 1} b_i \times b_j \\ \end{bmatrix}\\ \end{aligned} \]

那么接下来的事情就一目了然了,我们在计算时单取矩阵的第一列(行)进行计算,就可以优化到 \(O(n^2)\) 了。

所以就可以打出一份循环矩阵的模版:

template<class T,const int N>struct CMat{
	int n;
	T d[N];
	T &operator[](int i){
		return d[i];
	}
	CMat(int n=0):n(n){
		FOR(i,1,n)d[i]=0;
	}
	void Unit(){
		d[1]=1;
	}
	friend CMat operator *(CMat A,CMat B){
		CMat C(A.n);
		FOR(i,1,A.n)FOR(j,1,B.n)C[(i+j-2)%C.n+1]+=A[i]*B[j];
		return C;
	}
	friend CMat operator ^(CMat A,ll b){
		CMat res(A.n);
		for(res.Unit();b;b>>=1,A=A*A)if(b&1)res=res*A;
		return res;
	}
};

应用

BZOJ - 2510/4204

链接

  1. 弱题 - BZOJ 2510 - Virtual Judge (vjudge.net)
  2. 取球游戏 - BZOJ 4204 - Virtual Judge (vjudge.net)

分析

在每一次操作中,每个小球被重新编号的概率是 \(\frac{1}{m}\),而不改变的概率是 \(\frac{m-1}{m}\),那么如果我们设 \(f_{i,j}\) 表示经过了 \(i\) 次操作后,标号为 \(j\) 的球的期望个数,就可以列出如下的转移方程:

\[\begin{bmatrix} f_{i,1} & f_{i,2} & \cdots & f_{i,n} \\ \end{bmatrix} \begin{bmatrix} \frac{m-1}{m} & \frac{1}{m} & \cdots & 0 \\ 0 & \frac{m-1}{m} & \cdots & 0 \\ \vdots & \vdots & \ddots & \vdots \\ \frac{1}{m} & 0 & \cdots & \frac{m-1}{m} \\ \end{bmatrix} = \begin{bmatrix} f_{i+1,1} & f_{i+1,2} & \cdots & f_{i+1,n} \\ \end{bmatrix} \]

其中的转移矩阵明显是一个循环矩阵,我们用循环矩阵的方式优化矩阵快速幂就可以达到 \(O(n^2\log_2{k})\) 的时间复杂度,可以过掉本题。


posted @ 2024-08-21 07:41  Add_Catalyst  阅读(179)  评论(0)    收藏  举报