HDU6050 - 矩阵递推

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]);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值