01.斐波那契数列

1.解析

第一反应动态规划,时间复杂度必然是O(N),现在有个办法能把时间复杂度变为O(logN),我不确定这种办法能不能用在其它动态规划上。递推毫无争议,公式如下:
F ( N ) = F ( N − 1 ) + F ( N − 2 ) F(N) = F(N-1) + F(N-2) F(N)=F(N1)+F(N2)
  书上表示出了一种矩阵的格式,我也不知道是怎么推出的,只是说“二阶递推数列一定能够用矩阵的乘法表示”(这不就表示所有的递推都能用?DP大多数都是递推的)。
( F ( N ) , F ( N − 1 ) ) = ( F ( N − 1 ) , F ( N − 2 ) ) ∗ { a b c d } (F(N),F(N-1)) = (F(N-1),F(N-2)) * \left\{ \begin{matrix} a & b\\ c & d\\ \end{matrix} \right\} (F(N),F(N1))=(F(N1),F(N2)){acbd}
  abcd用试的就能试出来具体的值
( F ( 3 ) , F ( 2 ) ) = ( 1 , 1 ) ∗ { 1 1 1 0 } (F(3),F(2)) = (1,1) * \left\{ \begin{matrix} 1 & 1\\ 1 & 0\\ \end{matrix} \right\} (F(3),F(2))=(1,1){1110}

( F ( 4 ) , F ( 3 ) ) = ( 1 , 1 ) ∗ { 1 1 1 0 } 2 (F(4),F(3)) = (1,1) * \left\{ \begin{matrix} 1 & 1\\ 1 & 0\\ \end{matrix} \right\}^{2} (F(4),F(3))=(1,1){1110}2

( F ( N ) , F ( N − 1 ) ) = ( F ( N − 1 ) , F ( N − 2 ) ) ∗ { 1 1 1 0 } N − 2 (F(N),F(N-1)) = (F(N-1),F(N-2)) * \left\{ \begin{matrix} 1 & 1\\ 1 & 0\\ \end{matrix} \right\}^{N-2} (F(N),F(N1))=(F(N1),F(N2)){1110}N2

这就是新的递推公式,问题也就转换为了矩阵快速幂问题。矩阵快速幂问题在别的章节讲。

2.复杂度分析

时间复杂度就是将一个数字分割成二进制数后,二进制数的位数。因为是二进制数,所以应该是logN。只是感觉是这样,具体的证明没有,我也有点迷糊。

3.代码

写的有点乱,我一方面想要进行参数判断,一方面想要方便,蓝瘦

牛客已证

#include <iostream>
#include <vector>


using namespace std;

///<矩阵乘法,a和b是两个待乘的矩阵,c是返回值
bool multi_matrix(vector<vector<int> >a, vector<vector<int> >b, vector<vector<int> >&c)
{	
	if(a.empty() || b.empty() || c.empty())
		return false;
	vector<vector<int> >tmp(c.size(), vector<int>(c[0].size(), 0));
	c.assign(tmp.begin(), tmp.end());

	for(int i=0;i<(int)a.size();++i)
		for(int j=0;j<(int)b[0].size();++j)
			for(int k=0; k<(int)b.size();++k)
				c[i][j] += a[i][k] * b[k][j];
	return true;
}

///<矩阵快速幂乘法,m矩阵的p次幂,res是返回值,m不用引用会报段错误,我也不知道为啥
bool matrix_pow(vector<vector<int> >&m, int p, vector<vector<int> >&res)
{
	if(m.empty())
		return false;

	vector<vector<int> >zero(m.size(), vector<int>(m[0].size(),0));
	res.assign(zero.begin(), zero.end());
	for(int i=0;i<(int)m.size();++i)
	{
		for(int j=0;j<(int)m[0].size();++j)	
		{
			if(i==j)
				res[i][j] = 1;
			else
				res[i][j] = 0;
		}
	}
	vector<vector<int> >tmp(m.begin(), m.end());
	while(0 != p)
	{
		if(0 != (p&1))
			multi_matrix(res,tmp,res);	
		multi_matrix(tmp,tmp,tmp);
		p>>=1;
	}
	
	return true;
}


int main(void)
{
	int a[2]={1,1};
	int b[2]={1,0};
	vector<int>c;
	c.assign(a,a+2);
	vector<int>d;
	d.assign(b,b+2);
	vector<vector<int> >e;
	e.push_back(c);
	e.push_back(d);
	vector<vector<int> >res;
	int n ;
	cin>>n;
	if(1==n || 2==n)
		cout<<1<<endl;
	else
	{
		matrix_pow(e,n-2,res);
		cout<<res[0][0]+res[1][0]<<endl;
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tux~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值