02 UOJ(WHYZ) P14 数列 递推+矩阵快速幂

#14. 数列

题目描述

a[1]=a[2]=a[3]=1)

a[x]=a[x−3]+a[x−1](x>3)

       求a 数列的第 项对 1000000007 取余的值。

输入描述 第一行一个整数,表示询问个数。

以下行,每行一个正整数。

输出描述

每行输出一个非负整数表示答案。

样例输入

3
6
8
10

样例输出

4
9
19

时间限制、数据范围及描述

时间:1s 空间:256M

n<=2*10^9


题目链接

这道题目可以说是矩阵快速幂中的模板题了。题目中先看到递推式,再看数据范围,很明显告诉你不能在O(n)时间内完成。因此我们考虑矩阵快速幂的算法。在这道题目中,我们至少只需要保留f[n-1]和f[n-3]两个值就能推出f[n],但因为f[n+1]需要用到f[n-2]的值,所以我们在矩阵中也必须保留。这样,我们便能推出解题的矩阵{{1,0,1},{1,0,0},{0,1,0}},再运用矩阵快速幂即可在logn时间内完成。

AC代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
const int mod=1000000007;
struct jz{
	ll x[5][5];
};
jz mult(jz a,jz b){
	jz c;
	memset(c.x,0,sizeof(c.x));
	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++){
			for(int k=0;k<3;k++){
				c.x[i][j]=(c.x[i][j]+a.x[i][k]*b.x[k][j])%mod; 
			}
		}
	}
	return c;
}
jz qpow(jz m,int n){
	jz mul={{1,0,0,1}};
	while(n){
		if(n&1){
			mul=mult(mul,m);
		}
		n>>=1;
		m=mult(m,m);
	} 
	return mul;
}
int main(){
	int n,t;
	scanf("%d",&t);
	while(t--){
		jz m,ans;
		m.x[0][0]=m.x[0][2]=m.x[1][0]=m.x[2][1]=1;
		m.x[0][1]=m.x[1][1]=m.x[1][2]=m.x[2][2]=m.x[2][0]=0;
		scanf("%d",&n);
		ans=qpow(m,n-1);
		printf("%d\n",ans.x[0][0]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jialiang2509/article/details/80382406
今日推荐