您的位置:首页 > 其它

九度OJ 1089 递推数列

2016-08-05 21:43 295 查看
题目描述:

给定a0,a1,以及an=p*a(n-1) + q*a(n-2)中的p,q。这里n >= 2。 求第k个数对10000的模。
输入:

输入包括5个整数:a0、a1、p、q、k。

输出:

第k个数a(k)对10000的模。
样例输入:
20 1 1 14 5

样例输出:

8359


本题用常规做法,时间复杂度为O(n),必定超时。用矩阵快速幂改进之后,时间复杂度提高到O(logn)
注意到本题的规律:



那么,求Ak,我们就可以用以下式子:



下面就是如何求矩阵[p q; 1 0]的(k-1)次幂。
矩阵快速幂的关键思想是利用二进制位来减少乘积的次数。
例如:A^(101010) = A^(100000) + A^(00000)+A^(1010)+A^(000)+A^(10)+A^(0)
什么意思呢,也就是说,求一个A的101010次方,我们可以转化成右边的式子,减少乘法的次数。
结合代码讲:
N表示幂,res表示要求的结果,初值为1,A表示底
while(N){
if(N & 1){
res = res * A; //表示该位值为1,就要把该位对应的数乘进来
}
N >>= 1; //右移一位,即判断下一个高位
A = A * A; //每次指针向前指一位,变成原来的平方
}

分析:当指针指向末位的0,res的值不动,右移一位,基值Adouble一下,变为A^2;
下一次指针指向左边的1时,res = res * A^2,表示该位要乘进来,然后继续下去。也就是说,如果哪位是1,将该位对应的A^? 乘进来,就是这么回事。
本题中只要将A换成矩阵,数的运算,重新定义矩阵的乘法运算即可。还要注意前两个数是特例,不能带入递推式子。
#include <iostream>
#include <cstring>
#define mod 10000
using namespace std;

typedef long long ll;
ll a0,a1,p,q,k;

typedef struct Matrix{
int num[2][2];
void init(){
memset(num,0,sizeof(num));
for(int i=0;i<2;i++)
num[i][i] = 1;
}
}Matrix;

Matrix multi(Matrix X,Matrix Y){
Matrix Result;
Result.num[0][0] = Result.num[0][1] = Result.num[1][0] = Result.num[1][1] = 0;
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
for(int k=0;k<2;k++){
Result.num[i][j] += X.num[i][k]*Y.num[k][j];
}
Result.num[i][j] = Result.num[i][j] % mod;
}
}
return Result;
}

void calculation(int N){
Matrix A;
A.num[0][0] = p;
A.num[0][1] = q;
A.num[1][0] = 1;
A.num[1][1] = 0;
Matrix res;
res.init();
while(N){
if(N & 1)
res = multi(res,A);
N >>= 1;
A = multi(A,A);
}
cout<<(res.num[0][0]*a1+res.num[0][1]*a0)%mod<<endl;
}

int main(){
while(cin>>a0>>a1>>p>>q>>k){
if(k == 0)
cout<<a0%mod<<endl;
else if(k == 1)
cout<<a1%mod<<endl;
else{
calculation(k-1);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: