bzoj3240 [NOI2013]矩阵游戏
有一个递推式 \(f_{i,\ j}\) 满足:
\[\begin{cases}f_{1,\ 1}=1\\f_{i,\ j}=a\times f_{i,\ j-1}+b&(j\neq1)\\f_{i,\ 1}=c\times f_{i-1,\ m}+d&(i\neq1)\end{cases} \]求 \(f_{n,\ m} \bmod (10^9+7)\)
\(n,\ m\leq10^{10^6},\ a,\ b,\ c,\ d\in[1,\ 10^9]\)
矩阵加速,数论
易知上式是有循环节的,循环节长度为 \(P-1\) ,因此 \(f_{n,\ m}=f_{n\bmod (P-[a\neq1]),\ m\bmod (P-[c\neq1])}\) (需特判 \(a=1\) 或 \(c=1\) 的情况 )
对于每一行,很容易就能构造出 \(\begin{bmatrix}f_{i,\ j}&b\end{bmatrix}\begin{bmatrix}a&0\\1&1\end{bmatrix}=\begin{bmatrix}f_{i,\ j+1}&b\end{bmatrix}\) ,即 \(\begin{bmatrix}f_{i,\ 1}&b\end{bmatrix}\begin{bmatrix}a&0\\1&1\end{bmatrix}^{m-1}=\begin{bmatrix}f_{i,\ m}&b\end{bmatrix}\)
但是相邻行的转移貌 \(\begin{bmatrix}f_{i,m}&d\end{bmatrix}\begin{bmatrix}c&0\\1&1\end{bmatrix}=\begin{bmatrix}f_{i+1,1}&d\end{bmatrix}\) 似并不能与上式结合……
\(\begin{bmatrix}f_{i+1,1}&d\end{bmatrix}\) 看着很不爽,我们将它化成 \(\begin{bmatrix}f_{i,\ m}&b\end{bmatrix}\begin{bmatrix}c&0\\\frac{d}{b}&1\end{bmatrix}=\begin{bmatrix}f_{i,\ j+1}&b\end{bmatrix}\)
令 \(M=\begin{bmatrix}a&0\\1&1\end{bmatrix}^{m-1},\ N=\begin{bmatrix}c&0\\\frac{d}{b}&1\end{bmatrix}\)
可以发现最终答案 \(A=\begin{bmatrix}f_{1,\ 1}&b\end{bmatrix}\times M\times N\times M\times N\cdots\times M\) (即从 \(f_{i,\ 1}\) 转移到 \(f_{i,\ m}\) 再转移到 \(f_{i+1,\ 1}\) ,且第 \(n\) 行不用乘以 \(N\) )
因此将 \(M\times N\) 结合一下,原式 \(A=\begin{bmatrix}f_{1,\ 1}&b\end{bmatrix}\times (M\times N)^{n-1}\times M\)
时间复杂度 \(O(\log n+\log m)\)
代码
#include <bits/stdc++.h>
using namespace std;
#define rep(i) for (int i = 0; i < 2; i++)
const int maxn = 1e6 + 10, P = 1e9 + 7;
int n, m, a, b, c, d;
char str1[maxn], str2[maxn];
struct matrix {
int arr[2][2];
matrix() { memset(arr, 0, sizeof arr); }
int* operator [] (const int &pos) {
return arr[pos];
}
} E;
inline int inc(int x, int y) {
return x + y < P ? x + y : x + y - P;
}
matrix operator + (matrix a, matrix b) {
rep(i) rep(j) a[i][j] = inc(a[i][j], b[i][j]);
return a;
}
matrix operator * (matrix a, matrix b) {
matrix res;
rep(k) rep(i) rep(j) {
res[i][j] = inc(res[i][j], 1ll * a[i][k] * b[k][j] % P);
}
return res;
}
matrix qp(matrix a, int k) {
matrix res = E;
for (; k; k >>= 1, a = a * a) {
if (k & 1) res = res * a;
}
return res;
}
int qp(int a, int k) {
int res = 1;
for (; k; k >>= 1, a = 1ll * a * a % P) {
if (k & 1) res = 1ll * res * a % P;
}
return res;
}
int main() {
E[0][0] = E[1][1] = 1;
scanf("%s %s %d %d %d %d", str1 + 1, str2 + 1, &a, &b, &c, &d);
int nP = P - (a != 1), mP = P - (c != 1);
int len1 = strlen(str1 + 1), len2 = strlen(str2 + 1);
for (int i = 1; i <= len1; i++) {
n = (10ll * n + str1[i] - 48) % nP;
}
for (int i = 1; i <= len2; i++) {
m = (10ll * m + str2[i] - 48) % mP;
}
if (!n) n = nP;
if (!m) m = mP;
matrix A, M, N;
M[1][0] = M[1][1] = N[1][1] = 1;
N[1][0] = 1ll * d * qp(b, P - 2) % P;
A[0][0] = 1, A[0][1] = b, M[0][0] = a, N[0][0] = c;
M = qp(M, m - 1);
A = A * qp(M * N, n - 1) * M;
printf("%d", A[0][0]);
return 0;
}