http://acm.hdu.edu.cn/showproblem.php?pid=6050
SOURCE: 2017 Multi-University Training Contest - Team 2
题意:
给定 $ n $ , $ m $ , 求 $ F_{m,1} $
题解:
首先对基础递推式$$F_{1,i}=F_{1,i-1}+2\times F_{1,i-2}$$加一个sigma,有
$$\sum_{i=j}^{j+N-1} F_{1,i} = \sum_{i=j-1}^{j+N-2} F_{1,i} + 2\sum_{i=j-2}^{j+N-3}F_{1,i}$$
即
$$F_{2,j} = F_{2,j-1} +2 F_{2,j-2}$$
归纳下去可得
$$F_{i,j} = F_{i,j-1} + 2F_{i,j-2}$$
所以基础递推式对任意行标$i$都成立。先来递推列,设矩阵
$$A_{i}=\begin{bmatrix}
F_{i,1} &F_{i,2}&F_{i,1}&F_{i,2}
\end{bmatrix},B=\begin{bmatrix}
0 &2&0&2\\
1& 1& 1 &1 \\
0& 0 & 1 & 0\\
0 & 0 &0 & 1
\end{bmatrix}$$
则
$$A_{i}B=\begin{bmatrix}
F_{i,2} &F_{i,3}&F_{i,1}+F_{i,2}&F_{i,2}+F_{i,3}\\
\end{bmatrix}$$
$$A_{i}B^{n-1}=\begin{bmatrix}
F_{i,n} &F_{i,n+1}&\sum_{j=1}^{n}F_{i,j}&\sum_{j=2}^{n+1}F_{i,j}\\
\end{bmatrix}$$
$$=\begin{bmatrix}
F_{i,n} &F_{i,n+1}&F_{i+1,1}&F_{i+1,2}
\end{bmatrix}$$
利用B矩阵递推出了下一行的前两个元素,为了使用快速幂递推行,我们再构造一个矩阵把$A_{i}B^{n-1}$调整到$A_{i+1}$的形式。令
$$C=\begin{bmatrix}
0&0&0&0\\
0& 0& 0 &0 \\
1& 0 & 1 & 0\\
0 & 1 &0 & 1
\end{bmatrix}$$
则有
$$A_{i}B^{n-1}C=\begin{bmatrix}
F_{i+1,1} &F_{i+1,2}&F_{i+1,1}&F_{i+1,2}\\
\end{bmatrix}=A_{i+1}$$
那么就有
$$A_{m}=A_{1}(B^{n-1}C)^{m-1}$$
求出$A_{m}$即得到答案。
然而这个题用4x4的矩阵会被卡常数....(官方题解是分奇偶2x2矩阵递推)
丧心病狂的常数优化一下之后也能过,我加了读入优化又把矩阵的struct拆成数组之后700ms卡过去了....
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <map>
#include <set>
#include <ctime>
#include <queue>
#define LL long long
using namespace std;
const int MOD = (int)(1e9)+7, maxN = 5, maxn = 5;
#define LL long long
const LL UP = (LL)10000000*MOD;
void get(int &x)
{
char c = getchar(); x = 0;
while(c < '0' || c > '9') c = getchar();
while(c <= '9' && c >= '0') x = x*10+c-48, c = getchar();
}
void get(LL &x)
{
char c = getchar(); x = 0;
while(c < '0' || c > '9') c = getchar();
while(c <= '9' && c >= '0') x = x*10+c-48, c = getchar();
}
void put(LL x)
{
int num = 0; char c[15];
while(x) c[++num] = (x%10)+48, x /= 10;
while(num) putchar(c[num--]);
putchar('\n');
}
int c[maxn][maxn];
void mul(int a[maxN][maxN], int b[maxN][maxN], int _c[maxN][maxN])
{
memset(c, 0, sizeof(c));
LL tmp;
for(int i = 1; i <= 4; i++)
{
tmp = 0;
for(int j = 1; j <= 4; j++)
{
for(int k = 1; k <= 4; k++)
{
tmp += 1ll* a[i][k] * b[k][j];
if(tmp>=UP) tmp%=MOD;
}
c[i][j] = tmp%MOD;
tmp = 0;
}
}
for(int i = 1; i <= 4; i++) for(int j = 1; j <= 4; j++) _c[i][j] = c[i][j];
}
int tmp[maxN][maxN], a[maxN][maxN];
void pow(int _a[maxN][maxN], LL x, int _b[maxN][maxN])
{
for(int i = 1; i <= 4; i++) for(int j = 1; j <= 4; j++) a[i][j] = _a[i][j];
memset(tmp, 0, sizeof(tmp));
for(int i=1; i <= 4; i++) tmp[i][i]=1;
for(;x;mul(a,a,a),x>>=1) if(x&1) mul(tmp, a, tmp);
for(int i = 1; i <= 4; i++) for(int j = 1; j <= 4; j++) _b[i][j] = tmp[i][j];
}
int A[maxN][maxN], B[maxN][maxN], C[maxN][maxN], b[maxN][maxN];
int main()
{
#ifndef ONLINE_JUDGE
freopen("1006_in.txt", "r", stdin);
freopen("test_out.txt", "w", stdout);
#endif
int T;
memset(A, 0, sizeof(A));
memset(B, 0, sizeof(B));
memset(C, 0, sizeof(C));
A[1][1] = A[1][2] = A[1][3] = A[1][4] = 1;
B[1][2] = 2; B[1][4] = 2;
B[2][1]=B[2][2]=B[2][3]=B[2][4]=1;
B[3][3] = 1; B[4][4] = 1;
C[3][1] = C[3][3] = C[4][2] = C[4][4] = 1;
get(T);
while(T--)
{
LL n, m;
get(n); get(m);
pow(B, n-1, b);
mul(b, C, b);
pow(b, m-1, b);
mul(A, b, b);
// b = B^(n-1); b=b*C;
// b = b^(m-1);
// b = A*b;
put(b[1][1]);
}
}