PKOJ 3070 矩阵快速幂问题

来源:互联网 发布:国家外汇管理局 知乎 编辑:程序博客网 时间:2024/06/06 04:00

原题传送门:http://acm.pku.edu.cn/JudgeOnline/problem?id=3070


快速幂是一种能够将高次方运算的时间复杂度降低到O(log n)级别的算法

比如计算 2^8 用常规的算法是 2*2*2*2*2*2*2*2 这样计算机需要运算7次

但是如果我们先算出2*2 然后再将所得结果乘以自己三次 即(2*2)*(2*2)*(2*2)*(2*2)这样一来只需要运算4次

当然还可以继续优化 比如得到2^2之后再乘以自己 就得到了2^4 这样原来的2^8就可以变为2 * 2 * 2^2 * 2^4 那么就只需要运算3次


以上就是快速幂的基本思想了 


有了基本思想 我们就可以把任意的高次幂简化 具体做法如下

比如 a^11 我们需要先把指数转换成二进制 11的二进制是1011

即11=2^0+2^1+2^3

那么a^11就变成了 a^(2^0) * a^(2^1) * a^(2^3)


先贴上快速幂的代码

int mypow(int a,int b){    int ans=1,base=a;    while(b){        if(b&1)          ans*=base;        base*=base;        b>>=1;  }    return ans;}
计算机的存储本身就是二进制 所以我们可以直接进行按位操作 从二进制的第一位开始 每进一位 base就自乘 若当前位为1 代表答案的ans变量就乘上base

快速幂就这么简单



但是要想解决这个问题 光是了解快速幂还不够 我们还需要了解矩阵乘法的运算方法

简单讲一下矩阵乘法吧 本题也没有涉及特别高深的层面 



首先 进行矩阵乘法的两个矩阵必须满足 第一个矩阵的列数等于第二个矩阵的行数

满足这个条件后 就可以进行矩阵的乘法运算了 


得到的乘积矩阵有以下性质 

乘积矩阵的行数等于第一个矩阵的行数 乘积矩阵的列数等于第二个矩阵的列数


举一个简单易懂的例子


比如 第一个矩阵是

a1 a2 a3

a4 a5 a6

第二个矩阵是

b1 b2

b3 b4

b5 b6

那么 得到的乘积矩阵为

a1*b1+a2*b3+a3*b5   a1*b2+a2*b4+a3*b6

a4*b1+a5*b3+a6*b5   a4*b2+a5*b4+a6*b6


OK 有了以上的知识 这道题就变得像A+B一样简单了


直接贴代码

#include<cstdio>#include<iostream>using namespace std;struct matrix{int a[2][2];}ans,base;matrix C(matrix x,matrix y){matrix t;int i,j,k;for(i=0;i<2;i++)for(j=0;j<2;j++){t.a[i][j]=0;for(k=0;k<2;k++){t.a[i][j]=(t.a[i][j]+x.a[i][k]*y.a[k][j])%10000;}}return t;}int fast(int n){ans.a[0][0]=ans.a[1][1]=1;ans.a[1][0]=ans.a[0][1]=0;base.a[0][0]=base.a[0][1]=base.a[1][0]=1;base.a[1][1]=0;while(n){if(n&1){ans=C(ans,base);}base=C(base,base);n>>=1;}return ans.a[0][1];}int main(){int n;while(scanf("%d",&n)!=EOF && n!=-1){printf("%d\n",fast(n));}return 0;}