洛谷P1939 【模板】矩阵加速(数列)

传送门

题意

$a_1=a_2=a_3=1$

$a_n=a_{n-3}+a_{n-1}\quad(n>3)$

有$T$组询问。对每组询问,给定$n$,求$a_n\mod 1000000007$。

$T\leq 100,n\leq 2\times 10^9$。

题解

首先假定你会矩阵快速幂(不会的看:这里

那么,我们可以构造列向量

$$C_{n}=\begin{bmatrix}a_{n-2}\\a_{n-1}\\a_{n}\end{bmatrix}$$

,然后想办法构造一个$3x3$的矩阵$A$,使得

$$A\times C_{n}=C_{n+1}$$

显然,$A$可以等于

$$\begin{bmatrix}0&1&0\\0&0&1\\1&0&1\end{bmatrix}$$

然后矩阵快速幂一波就可以在$\mathcal O(\lg n)$的时间内求出$a_{n}$了。

贴代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef array<array<ll, 4>, 4> Matrix;
const ll P = 1000000007;

ll n, k;
Matrix A, I;

Matrix MatrixMul(const Matrix &A, const Matrix &B) {
	Matrix ret;
	for (int i=1; i<=n; i++)
		for (int j=1; j<=n; j++) {
			ret[i][j] = 0;
			for (int k=1; k<=n; k++)
				(ret[i][j] += A[i][k] * B[k][j] % P) %= P;
		}
	return ret;
}
Matrix PowerMod(ll k) {
	if (k == 0) return I;
	if (k == 1) return A;
	if (k & 1) return MatrixMul(PowerMod(k-1), A);
	Matrix B = PowerMod(k >> 1);
	return MatrixMul(B, B);
}

signed main() {
	int T; scanf("%d", &T);
	n = 3; I[1][1] = I[2][2] = I[3][3] = 1;
	A[1][2] = A[2][3] = A[3][1] = A[3][3] = 1;
	while (T--) {
		int n; scanf("%d", &n);
		if (n <= 3) puts("1");
		else {
			Matrix ret = PowerMod(n - 3);
			printf("%lld\n", (ret[3][1] + ret[3][2] + ret[3][3]) % P);
		}
	}
	return 0;
}
posted @ 2018-07-23 11:23  MCH__ds  阅读(215)  评论(0编辑  收藏  举报