九度OJ 1089 递推数列

来源:互联网 发布:python官网下载有64 编辑:程序博客网 时间:2024/04/29 17:27
题目描述:

给定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 10000using 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;}



0 0
原创粉丝点击