信息学奥赛一本通 1644:【例 4】佳佳的 Fibonacci

【题目链接】

ybt 1644:【例 4】佳佳的 Fibonacci

【题目考点】

1. 矩阵加速递推

相关知识见:矩阵加速递推模板题

【解题思路】

解法1:转移矩阵为五阶矩阵

构造转移矩阵

已知: T n = F 1 + 2 F 2 + . . . + ( n − 1 ) F n − 1 + n F n T_n=F_1+2F_2+...+(n-1)F_{n-1}+nF_n Tn=F1+2F2+...+(n−1)Fn−1+nFn

所以: T n − 1 = F 1 + . . . + ( n − 1 ) F n − 1 T_{n-1}=F_1+...+(n-1)F_{n-1} Tn−1=F1+...+(n−1)Fn−1

直观考虑可以得到: T n = T n − 1 + n F n T_n=T_{n-1}+nF_n Tn=Tn−1+nFn,但转移矩阵中不可以出现 n n n这样随着递推进行而变化的变量,因此可以考虑将 n F n nF_n nFn作为一个整体看待。

设 G n = n F n G_n=nF_n Gn=nFn,则 T n = T n − 1 + G n T_n=T_{n-1}+G_n Tn=Tn−1+Gn。

该递推式中出现了 G n G_n Gn, G n G_{n} Gn的下一项为 G n + 1 G_{n+1} Gn+1

根据递推式右侧的每一项,在等号左侧都要出现其下一项 ,我们需要写出 G n + 1 G_{n+1} Gn+1的递推式。
G n + 1 = ( n + 1 ) F n + 1 = ( n + 1 ) ( F n + F n − 1 ) = F n + n F n + 2 F n − 1 + ( n − 1 ) F n − 1 = F n + 2 F n − 1 + G n + G n − 1 G_{n+1}=(n+1)F_{n+1}=(n+1)(F_{n}+F_{n-1})\\ =F_n+nF_n+2F_{n-1}+(n-1)F_{n-1}\\ =F_n+2F_{n-1}+G_n+G_{n-1} Gn+1=(n+1)Fn+1=(n+1)(Fn+Fn−1)=Fn+nFn+2Fn−1+(n−1)Fn−1=Fn+2Fn−1+Gn+Gn−1

  • 该式右侧出现了 G n − 1 G_{n-1} Gn−1,其下一项为 G n G_n Gn,在等号右侧已经存在。
  • 该式右侧出现了 F n F_n Fn, F n F_n Fn的下一项为 F n + 1 F_{n+1} Fn+1,可以写出递推式: F n + 1 = F n + F n − 1 F_{n+1}=F_n+F_{n-1} Fn+1=Fn+Fn−1。 F n F_n Fn与 F n − 1 F_{n-1} Fn−1在等号右侧已经存在。
  • 该式右侧出现了 F n − 1 F_{n-1} Fn−1, F n − 1 F_{n-1} Fn−1的下一项为 F n F_n Fn,等号右侧已有了 F n F_n Fn,因此可以写为 F n = F n F_n=F_n Fn=Fn。

整合以上递推式:
T n = 1 ⋅ T n − 1 + 1 ⋅ G n + 0 ⋅ G n − 1 + 0 ⋅ F n + 0 ⋅ F n − 1 T_n = 1\cdot T_{n-1}+1\cdot G_n+0\cdot G_{n-1}+0\cdot F_n+0\cdot F_{n-1} Tn=1⋅Tn−1+1⋅Gn+0⋅Gn−1+0⋅Fn+0⋅Fn−1
G n + 1 = 0 ⋅ T n − 1 + 1 ⋅ G n + 1 ⋅ G n − 1 + 1 ⋅ F n + 2 ⋅ F n − 1 G_{n+1}=0\cdot T_{n-1}+1\cdot G_n+1\cdot G_{n-1}+1\cdot F_n+2\cdot F_{n-1} Gn+1=0⋅Tn−1+1⋅Gn+1⋅Gn−1+1⋅Fn+2⋅Fn−1
G n = 0 ⋅ T n − 1 + 1 ⋅ G n + 0 ⋅ G n − 1 + 0 ⋅ F n + 0 ⋅ F n − 1 G_{n}=0\cdot T_{n-1}+1\cdot G_n+0\cdot G_{n-1}+0\cdot F_n+0\cdot F_{n-1} Gn=0⋅Tn−1+1⋅Gn+0⋅Gn−1+0⋅Fn+0⋅Fn−1
F n + 1 = 0 ⋅ T n − 1 + 0 ⋅ G n + 0 ⋅ G n − 1 + 1 ⋅ F n + 1 ⋅ F n − 1 F_{n+1}=0\cdot T_{n-1}+0\cdot G_n+0\cdot G_{n-1}+1\cdot F_n+1\cdot F_{n-1} Fn+1=0⋅Tn−1+0⋅Gn+0⋅Gn−1+1⋅Fn+1⋅Fn−1
F n = 0 ⋅ T n − 1 + 0 ⋅ G n + 0 ⋅ G n − 1 + 1 ⋅ F n + 0 ⋅ F n − 1 F_{n}=0\cdot T_{n-1}+0\cdot G_n+0\cdot G_{n-1}+1\cdot F_n+0\cdot F_{n-1} Fn=0⋅Tn−1+0⋅Gn+0⋅Gn−1+1⋅Fn+0⋅Fn−1

写成矩阵形式:
T n G n + 1 G n F n + 1 F n = 1 1 0 0 0 0 1 1 1 2 0 1 0 0 0 0 0 0 1 1 0 0 0 1 0 T n − 1 G n G n − 1 F n F n − 1 = 1 1 0 0 0 0 1 1 1 2 0 1 0 0 0 0 0 0 1 1 0 0 0 1 0 n − 1 T 1 G 2 G 1 F 2 F 1 \begin{bmatrix}T_n\\G_{n+1}\\G_n\\F_{n+1}\\F_n\end{bmatrix}=\begin{bmatrix}1&1&0&0&0\\0&1&1&1&2\\0&1&0&0&0\\0&0&0&1&1\\0&0&0&1&0\end{bmatrix}\begin{bmatrix}T_{n-1}\\G_{n}\\G_{n-1}\\F_{n}\\F_{n-1}\end{bmatrix}=\begin{bmatrix}1&1&0&0&0\\0&1&1&1&2\\0&1&0&0&0\\0&0&0&1&1\\0&0&0&1&0\end{bmatrix}^{n-1}\begin{bmatrix}T_{1}\\G_{2}\\G_{1}\\F_{2}\\F_{1}\end{bmatrix} TnGn+1GnFn+1Fn = 1000011100010000101102010 Tn−1GnGn−1FnFn−1 = 1000011100010000101102010 n−1 T1G2G1F2F1

其中 T 1 = G 1 = F 2 = F 1 = 1 , G 2 = 2 T_1=G_1=F_2=F_1=1, G_2=2 T1=G1=F2=F1=1,G2=2

使用矩阵加速递推算法,即可得到结果 T n T_n Tn。

解法2:转移矩阵为四阶矩阵

已知: T n = F 1 + 2 F 2 + . . . + ( n − 1 ) F n − 1 + n F n T_n=F_1+2F_2+...+(n-1)F_{n-1}+nF_n Tn=F1+2F2+...+(n−1)Fn−1+nFn

如果希望最后的 F n F_n Fn前的系数为常数,可以让 T n T_n Tn减掉 n F n nF_n nFn,顺着这个思路往下想。

设 S n = F 1 + F 2 + . . . + F n S_n=F_1+F_2+...+F_n Sn=F1+F2+...+Fn,那么可以考虑让 n S n nS_n nSn减掉 T n T_n Tn

设 P n = n S n − T n = ( n − 1 ) F 1 + ( n − 2 ) F 2 + . . . + 2 F n − 2 + F n − 1 P_n=nS_n-T_n=(n-1)F_1+(n-2)F_2+...+2F_{n-2}+F_{n-1} Pn=nSn−Tn=(n−1)F1+(n−2)F2+...+2Fn−2+Fn−1

那么 P n − 1 = ( n − 2 ) F 1 + ( n − 3 ) F 2 + . . . + 2 F n − 3 + F n − 2 P_{n-1}=(n-2)F_1+(n-3)F_2+...+2F_{n-3}+F_{n-2} Pn−1=(n−2)F1+(n−3)F2+...+2Fn−3+Fn−2

那么 P n = P n − 1 + F 1 + . . . + F n − 1 = P n − 1 + S n − 1 P_n=P_{n-1}+F_1+...+F_{n-1}=P_{n-1}+S_{n-1} Pn=Pn−1+F1+...+Fn−1=Pn−1+Sn−1

等式右侧出现了 S n − 1 S_{n-1} Sn−1,那么等式左侧需要有 S n S_n Sn
S n = S n − 1 + F n S_n=S_{n-1}+F_n Sn=Sn−1+Fn

等式右侧出现了 F n F_n Fn,等式左侧需要有 F n + 1 F_{n+1} Fn+1
F n + 1 = F n + F n − 1 F_{n+1}=F_n+F_{n-1} Fn+1=Fn+Fn−1

等式右侧出现了 F n − 1 F_{n-1} Fn−1,等式左侧需要有 F n F_n Fn
F n = F n F_n=F_n Fn=Fn

整合上述递推式:
P n = 1 ⋅ P n − 1 + 1 ⋅ S n − 1 + 0 ⋅ F n + 0 ⋅ F n − 1 P_n=1\cdot P_{n-1}+1\cdot S_{n-1}+0\cdot F_n+0\cdot F_{n-1} Pn=1⋅Pn−1+1⋅Sn−1+0⋅Fn+0⋅Fn−1
S n = 0 ⋅ P n − 1 + 1 ⋅ S n − 1 + 1 ⋅ F n + 0 ⋅ F n − 1 S_n=0\cdot P_{n-1}+1\cdot S_{n-1}+1\cdot F_n+0\cdot F_{n-1} Sn=0⋅Pn−1+1⋅Sn−1+1⋅Fn+0⋅Fn−1
F n + 1 = 0 ⋅ P n − 1 + 0 ⋅ S n − 1 + 1 ⋅ F n + 1 ⋅ F n − 1 F_{n+1}=0\cdot P_{n-1}+0\cdot S_{n-1}+1\cdot F_n+1\cdot F_{n-1} Fn+1=0⋅Pn−1+0⋅Sn−1+1⋅Fn+1⋅Fn−1
F n = 0 ⋅ P n − 1 + 0 ⋅ S n − 1 + 1 ⋅ F n + 0 ⋅ F n − 1 F_{n}=0\cdot P_{n-1}+0\cdot S_{n-1}+1\cdot F_n+0\cdot F_{n-1} Fn=0⋅Pn−1+0⋅Sn−1+1⋅Fn+0⋅Fn−1

写出矩阵形式:
P n S n F n + 1 F n = 1 1 0 0 0 1 1 0 0 0 1 1 0 0 1 0 P n − 1 S n − 1 F n F n − 1 = 1 1 0 0 0 1 1 0 0 0 1 1 0 0 1 0 n − 1 P 1 S 1 F 2 F 1 \begin{bmatrix}P_n\\S_n\\F_{n+1}\\F_n\end{bmatrix}=\begin{bmatrix}1&1&0&0\\0&1&1&0\\0&0&1&1\\0&0&1&0\end{bmatrix}\begin{bmatrix}P_{n-1}\\S_{n-1}\\F_n\\F_{n-1}\end{bmatrix}=\begin{bmatrix}1&1&0&0\\0&1&1&0\\0&0&1&1\\0&0&1&0\end{bmatrix}^{n-1}\begin{bmatrix}P_{1}\\S_{1}\\F_2\\F_{1}\end{bmatrix} PnSnFn+1Fn = 1000110001110010 Pn−1Sn−1FnFn−1 = 1000110001110010 n−1 P1S1F2F1

其中 P 1 = S 1 − T 1 = 0 , S 1 = F 2 = F 1 = 1 P_1=S_1-T_1=0, S_1=F_2=F_1=1 P1=S1−T1=0,S1=F2=F1=1

使用矩阵加速递推算法,求出结果矩阵。结果矩阵中包含 P n P_n Pn与 S n S_n Sn。

已知 P n = n S n − T n P_n=nS_n-T_n Pn=nSn−Tn,那么本题结果 T n = ( n S n − P n )   m o d   m T_n=(nS_n-P_n)\bmod m Tn=(nSn−Pn)modm

注意: n S n − P n nS_n-P_n nSn−Pn可能为负数,要使用数学取模。

【题解代码】

解法1:转移矩阵为五阶矩阵

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define N 6
typedef long long LL;
LL n, m;
struct Mat
{
	LL n, a[N][N] = {};
	Mat(){}
	Mat(int _n, int val = 0):n(_n)
	{
		for(int i = 1; i <= n; ++i)
			a[i][i] = val;
	}
	LL* operator [] (int i)
	{
		return a[i];
	}
	Mat operator * (Mat b)
	{
		Mat r(n);
		for(int i = 1; i <= n; ++i)
			for(int j = 1; j <= n; ++j)
				for(int k = 1; k <= n; ++k)
					r[i][j] = (r[i][j]+a[i][k]*b[k][j])%m;
		return r;
	}
};
Mat fastPow(Mat a, LL b)
{
	Mat r(a.n, 1);
	while(b > 0)
	{
		if(b%2 == 1)
			r = r*a;
		a = a*a;
		b /= 2;
	}
	return r;
}
int main()
{
	cin >> n >> m;
	if(n == 1)
		cout << 1%m;
	else
	{
		Mat t(5), f(5);
		t[1][1] = t[1][2] = t[2][2] = t[2][3] = t[2][4] = t[3][2] = t[4][4] = t[4][5] = t[5][4] = 1, t[2][5] = 2; 
		f[1][1] = f[3][1] = f[4][1] = f[5][1] = 1, f[2][1] = 2;
		Mat r = fastPow(t, n-1)*f;
		cout << r[1][1];	
	}
	return 0;
}

解法2:转移矩阵为四阶矩阵

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define N 5
typedef long long LL;
LL n, m;
struct Mat
{
	LL n, a[N][N] = {};
	Mat(){}
	Mat(int _n, int val = 0):n(_n)
	{
		for(int i = 1; i <= n; ++i)
			a[i][i] = val;
	}
	LL* operator [] (int i)
	{
		return a[i];
	}
	Mat operator * (Mat b)
	{
		Mat r(n);
		for(int i = 1; i <= n; ++i)
			for(int j = 1; j <= n; ++j)
				for(int k = 1; k <= n; ++k)
					r[i][j] = (r[i][j]+a[i][k]*b[k][j])%m;
		return r;
	}
};
Mat fastPow(Mat a, LL b)
{
	Mat r(4, 1);
	while(b > 0)
	{
		if(b%2 == 1)
			r = r*a;
		a = a*a;
		b /= 2;
	}
	return r;
}
LL mod(LL a, LL b)
{
	return (a%m+b)%m;
}
int main()
{
	cin >> n >> m;
	if(n == 1)
		cout << 1%m;
	else
	{
		Mat t(4), f(4);
		t[1][1] = t[1][2] = t[2][2] = t[2][3] = t[3][3] = t[3][4] = t[4][3] = 1; 
		f[2][1] = f[3][1] = f[4][1] = 1;
		Mat r = fastPow(t, n-1)*f;
		cout << mod(n*r[2][1]-r[1][1], m);	
	}
	return 0;
}
相关推荐
cany100017 小时前
C++ -- 队列std::queue
开发语言·c++
周末也要写八哥17 小时前
C++中单线程方式之无脑上锁
java·开发语言·c++
cany100017 小时前
C++ -- 动态内存分配和释放(new/delete)
开发语言·c++
xcyxiner18 小时前
ubuntu下 cmake初始化脚本 以及 qt依赖
c++·qt
周末也要写八哥18 小时前
Visual C++6.0下载安装流程及PDF学习手册资源
c++·学习·pdf
熬夜敲代码的猫18 小时前
AVL树(C++详解版)
数据结构·c++·算法
思麟呀18 小时前
C++工业级日志项目(七)日志器核心
linux·开发语言·c++·windows
郝学胜_神的一滴18 小时前
Qt 高级开发 019:从零定制登录窗口按钮、Logo 样式与交互悬浮效果
c++·qt
lcj251118 小时前
vector的基本使用 + 手搓成员变量 size capacity begin end operator[] reserve扩容 拷贝构造 赋值析构
开发语言·c++·笔记·面试
liulilittle18 小时前
C++ do_div 宏
c++