洛谷 P1939 矩阵加速(数列)
题意简述
\(a[1]=a[2]=a[3]=1\)
\(a[x]=a[x−3]+a[x−1](x>3)\)
求a数列的第n项对1000000007取余的值。
题解思路
矩阵加速
设$$ F=\begin{bmatrix} 0&0&1\1&0&0\0&1&1\end{bmatrix}, G=\begin{bmatrix} 1\1\1\end{bmatrix}$$
则$$ \begin{bmatrix} a[n-3]\a[n-2]\a[n-1]\end{bmatrix} = G * F ^ {n-3} (n > 3)$$
代码
#include <cstdio>
typedef long long ll;
const int mod = 1000000007;
int n, T, N;
struct Matrix
{
int a[4][4];
Matrix& operator =(const Matrix& x)
{
for (register int i = 1; i <= N; ++i)
for (register int j = 1; j <= N; ++j)
a[i][j] = x.a[i][j];
return *this;
}
};
Matrix a, b, c;
Matrix Mul(const Matrix& x, const Matrix& y)
{
Matrix s;
for (register int i = 1; i <= N; ++i)
for (register int j = 1; j <= N; ++j)
s.a[i][j] = 0;
for (register int i = 1; i <= N; ++i)
for (register int j = 1; j <= N; ++j)
for (register int k = 1; k <= N; ++k)
s.a[i][j] = (s.a[i][j] + (ll)x.a[i][k] * y.a[k][j] % mod) % mod;
return s;
}
Matrix _pow(Matrix x, int y)
{
Matrix s;
for (register int i = 1; i <= N; ++i)
for (register int j = 1; j <= N; ++j)
s.a[i][j] = (i == j);
for (; y; y >>= 1, x = Mul(x, x)) if (y & 1) s = Mul(s, x);
return s;
}
int main()
{
N = 3;
scanf("%d", &T);
while (T--)
{
c.a[1][1] = c.a[1][2] = c.a[1][3] = 1;
a.a[1][3] = a.a[2][1] = a.a[3][2] = a.a[3][3] = 1;
scanf("%d", &n);
if (n <= 3) {printf("1\n"); continue; }
b = Mul(c, _pow(a, n - 3));
printf("%d\n", b.a[1][3]);
}
}