算法-骨牌覆盖问题(矩阵快速幂求Fibonacii)

在hihoCoder上遇到一道骨牌覆盖问题,分析后发现其实就是Fibonacii,但是要求高效的时间复杂度,也就是说传统递归方法实现是不能满足要求的。但是如果用快速幂方法求解的话,非常适用。

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB
描述

骨牌,一种古老的玩具。今天我们要研究的是骨牌的覆盖问题:
我们有一个2xN的长条形棋盘,然后用1x2的骨牌去覆盖整个棋盘。对于这个棋盘,一共有多少种不同的覆盖方法呢?
举个例子,对于长度为1到3的棋盘,我们有下面几种覆盖方式:

提示:骨牌覆盖

提示:如何快速计算结果

输入

第1行:1个整数N。表示棋盘长度。1≤N≤100,000,000

输出

第1行:1个整数,表示覆盖方案数 MOD 19999997

样例输入
62247088
样例输出
17748018
#include <iostream>
using namespace std;
struct matrix{
	long long arr[2][2];
}base,res;
const int MOD = 19999997;
matrix matMulti(matrix a, matrix b)
{
	matrix temp;
	int i,j;
	for(i=0; i<2; i++)
		for(j=0; j<2; j++){
			temp.arr[i][j] = 0;
			for(int k=0; k<2; k++){
				temp.arr[i][j] = temp.arr[i][j]%MOD+a.arr[i][k]*b.arr[k][j]%MOD;
			}
		}
	return temp;
}
long long fastFibonacii(long n)
{
	base.arr[0][0]=base.arr[0][1]=base.arr[1][0]=1;
	base.arr[1][1]=0;
	res.arr[0][1]=res.arr[1][0]=1;
	res.arr[1][1]=0;
	res.arr[0][0]=1;
	while(n){
		if(n&1){
			res = matMulti(res, base);
		}
		base = matMulti(base,base);
		n >>= 1;
	}
	return res.arr[0][1];
}
int main()
{
	long n;
	while(cin>>n){
		cout<<fastFibonacii(n)%MOD<<endl;
	}
	system("pause");
	return 0;
}

用定义一个结构体,重载运算符:

#include <iostream>
using namespace std;

const int MOD = 19999997;
struct matrix{       //重载结构体
public:
	long long a;
	long long b;
	long long c;
	long long d;
	matrix &operator * (matrix &data){ //重载*
		long long tempa = a;
		long long tempb = b;
		long long tempc = c;
		long long tempd = d;
		a = tempa*data.a%MOD+tempb*data.c%MOD;
		b = tempa*data.b%MOD+tempb*data.d%MOD;
		c = tempc*data.a%MOD+tempd*data.c%MOD;
		d = tempc*data.b%MOD+tempd*data.d%MOD;
		return *this;
	}
	matrix &operator = (matrix &data){  //重载&
		a = data.a;
		b = data.b;
		c = data.c;
		d = data.d;
		return *this;
	}
};

long long fastFibonacci(long n)
{
	matrix res = {1,1,1,0};
	matrix base = {1,1,1,0};
	matrix temp;
	n++;
	while(n){
		if(n&1){
			res = res*base;
		}
		temp = base;
		base = base*temp;
		n >>=1;
	}
	return res.d;
}
int main()
{
	long n;
	while(cin>>n){
		cout<<fastFibonacci(n)%MOD<<endl;
	}
	system("pause");
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值