(前言:这是一道关于矩阵快速幂的问题,介绍矩阵快速幂之前,首先看“快速幂”问题。 在前面的博客里有记录到快速幂取模算法,不过总体的思想总是和取模运算混淆在一起,而忽略了“快速幂”运算本身。计算ab本来就是一个可以加速的过程,“快速幂取模”运算只不过是“快速幂”算法的一个应用罢了。)

一、快速幂运算

这次我们关注快速幂本身:

我们知道离散化处理信息是计算机的热点,把连续数据存储为二进制离散数据是计算机的硬件要求。那么快速幂运算能否也运用这一思想呢,答案是肯定的。

容易发现:A19  =  (A16)*(A2)*(A1),而我们在计算A16的过程中可以通过A8*A8来得到,而A8同样可以通过A4*A4来得到,这样以来本来需要16次乘法运算得到的只需要log(16)=4次即可。

  A*A = A2

  A2*A2 = A4

  A4*A4 = A8

  A8*A8 =A16

再举例计算A148.我们知道14810=100101002,也就有A148=A128*A16*A4. 观察二进制形式的因子,容易发现这样的规律早就在二进制表示中显露出来了:100101002=100000002+000100002+000001002 =128+16+4。

核心代码表示为:  (第3行代码每进行一次,二进制数就少了最后面的一个1。二进制数有多少个1就第3行代码就执行多少次。)

 //在一路的A^x次方(x=1,2,4,8,16,...)的结果中,res通过“n的二进制位的值”来选取组成自己的“元素”
 while(n){
     )
         res=res*A;
     n>>=;
     A=A*A;
 }    

测试:

 #include <iostream>
 using namespace std;
 //快速计算 A^n
 int main(){
     int A,n;
     ;
     cin>>A>>n;

     //在一路的A^x次方(x=1,2,4,8,16,...)的结果中,res通过“n的二进制位的值”来选取组成自己的“元素”
     while(n){
         )
             res=res*A;
         n>>=;
         A=A*A;
     }
     cout<<res;
 } 

有输入的A^n

二、快速幂取模   ab%c

现在对于ab我们已经拿到尚方宝剑了,我们知道指数运算往往是很容易突破数据储存长度的(long long int 也才64位),所以一些方案处理中要求的只是ab%c而已。(反正这类问题客观存在,你就当我为它的存在杜撰了一个理由吧)

这时候可以运用取模运算的性质:(a*a)%c = (a%c)(a%c)%c

那这样取模运算就可以“镶嵌”在快速幂运算中了:   (if语句中“b%2==1”和上面的“n&1”的写法是一样的)

 ;
 a%=c;
 ){
     ==){
         num=(num*a)%c;
     }
     b>>;     //这一步将b->log2(b)
     a=(a*a)%c;
 }

三、矩阵快速幂

矩阵快速幂的思想就是跟数的快速幂一样,不过是把“数”换成“矩阵”罢了,在之前的数的乘法运算是用“*”直接运算,而这里需要单独写一个两矩阵相乘的函数以供调用。

这里展示一个示例程序:

 #include <cstdlib>
 #include <cstring>
 #include <cstdio>
 #include <iostream>
 using namespace std;

 int N;

 struct matrix{
        ][];
 }origin,res;

 matrix multiply(matrix x,matrix y){
        matrix temp;
        memset(temp.a,,sizeof(temp.a));
        ;i<;i++) {
                ;j<;j++) {
                        ;k<;k++) {
                                temp.a[i][j]+=x.a[i][k]*y.a[k][j];
                        }
                }
        }
        return temp;
 }

 void init(){
      printf("随机数组如下:\n");
      ;i<;i++){
              ;j<;j++){
                      origin.a[i][j]=rand()%;
                      printf("%8d",origin.a[i][j]);
              }
              printf("\n");
      }
      printf("\n");
      memset(res.a,,sizeof(res.a));
      res.a[][]=res.a[][]=res.a[][]=;                  //将res.a初始化为单位矩阵
 }

 void calc(int n){
      printf("%d次幂结果如下:\n",n);
      while(n) {
              )
                     res=multiply(res,origin);
              n>>=;
              origin=multiply(origin,origin);
      } 

      ;i<;i++) {
              ;j<;j++)
                      printf("%8d",res.a[i][j]);
              printf("\n");
      }
      printf("\n");
 }

 int main(){
     while(cin>>N) {
             init();
             calc(N);
     }
     ;
 }

矩阵 快速幂 演示

四、矩阵快速幂的应用

矩阵题目的难点在于构造矩阵,一般用于有能够推出递推式的题目,推出递推式之后,发现递推O(n)的时间复杂度比较大,那么我们可以构造一个矩阵,然后用矩阵快速幂降低到log(n)的时间复杂度

在NYOJ 299中

Fk = A + A2 + A3 + … + Ak

F(k-1) = A + A2 + A3 + … + Ak-1

故 Fk = A + A*F(k-1)

那么可以构造矩阵:

(Fk ,1 ) =  (Fk-1 ,1) * (A,0; A,1) = (F1 , 1) * (A,0;A,1)K-1

这样就可以运用矩阵快速幂了。

参考:

2. http://www.cnblogs.com/yan-boy/archive/2012/11/29/2795294.html

3. http://blog.csdn.net/chenguolinblog/article/details/10309423

4. http://blog.csdn.net/y990041769/article/details/39694583

5. http://blog.csdn.net/y990041769/article/details/39716951

6. http://www.matrix67.com/blog/archives/276

NYOJ 299的更多相关文章

  1. 最长递增子序列问题 nyoj 17单调递增最长子序列 nyoj 79拦截导弹

    一,    最长递增子序列问题的描述 设L=<a1,a2,…,an>是n个不同的实数的序列,L的递增子序列是这样一个子序列Lin=<aK1,ak2,…,akm>,其中k1< ...

  2. NYOJ 1007

    在博客NYOJ 998 中已经写过计算欧拉函数的三种方法,这里不再赘述. 本题也是对欧拉函数的应用的考查,不过考查了另外一个数论基本定理:如何用欧拉函数求小于n且与n互质所有的正整数的和. 记eule ...

  3. NYOJ 998

    这道题是欧拉函数的使用,这里简要介绍下欧拉函数. 欧拉函数定义为:对于正整数n,欧拉函数是指不超过n且与n互质的正整数的个数. 欧拉函数的性质:1.设n = p1a1p2a2p3a3p4a4...pk ...

  4. NYOJ 333

    http://www.cppblog.com/RyanWang/archive/2009/07/19/90512.aspx?opt=admin 欧拉函数 E(x)表示比x小的且与x互质的正整数的个数. ...

  5. iOS $299刀企业证书申请的过程以及细节补充(二)

    上篇博客写的过程中,没有图,也没有相应的说明.这次再补充一些信息: 1.从 https://developer.apple.com/ios/enroll/dunsLookupForm.action 申 ...

  6. iOS $299刀企业证书申请的过程以及细节补充

    最近申请了iOS的 299刀企业证书,相关过程有些问题,分享出来,以便后来人参考. 申请的过程我主要参考了别人以前的文章,链接如下: 1.https://developer.apple.com/cn/ ...

  7. NYOJ 99单词拼接(有向图的欧拉(回)路)

    /* NYOJ 99单词拼接: 思路:欧拉回路或者欧拉路的搜索! 注意:是有向图的!不要当成无向图,否则在在搜索之前的判断中因为判断有无导致不必要的搜索,以致TLE! 有向图的欧拉路:abs(In[i ...

  8. nyoj 10 skiing 搜索+动归

    整整两天了,都打不开网页,是不是我提交的次数太多了? nyoj 10: #include<stdio.h> #include<string.h> ][],b[][]; int ...

  9. 简答哈希实现 (nyoj 138 找球号2)

    例题链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=138 代码目的:复习哈希用 代码实现: #include "stdio.h&qu ...

随机推荐

  1. Hive中Bucket的应用

    网友南京-李先森给了他收集的一些资料,如下: Buckets 对指定列计算 hash,根据 hash 值切分数据,目的是为了并行,每一个 Bucket 对应一个文件.如将 user 列分散至 32 个 ...

  2. CC/G++ 学习笔记

    CC/G++ 学习笔记 本文是<An introduction to GCC>的学习笔记,记录使用GCC/G++主要的实用技巧,本文讲述的知识基本上摘自本书,附带自己的一些体验.如果想详细 ...

  3. [实验]通过内核Patch去掉iOS-v4.3.3的沙盒特性

    环境: 1.Mac OS X 10.9.2 2.xcode 5.1.1 3.gcc 4.8 4.redsn0w 0.9.15b3 前提: 1.获取 iOS 4.3.3 的kernelcache,并解密 ...

  4. Linux网络编程(二)

    Linux网络编程(二) 使用多进程实现服务器并发访问. 采用多进程的方式实现服务器的并发访问的经典范例. 程序实现功能: 1.客户端从标准输入读入一行文字,发送到服务器. 2.服务器接收到客户端发来 ...

  5. 5个Unix命令

    5个Unix命令 原文: http://spin.atomicobject.com/2013/09/09/5-unix-commands/ 希望早几年知道的5个Unix命令 使用*nix系统已经有一段 ...

  6. ContentResolver + SqliteOpenHelper + ContentProvider 理解

    惭愧,现在才接触到ContentResolver的用法 这个类主要是Android用来实现应用程序之间数据共享的 一个应用程序可以将自己的数据完全暴露出去,外界更本看不到,也不用看到这个应用程序暴露的 ...

  7. jQuery图片切换插件jquery.cycle.js

    Cycle是一个很棒的jQuery图片切换插件,提供了非常好的功能来帮助大家更简单的使用插件的幻灯功能 下载cycle插件并引入,此时,注意把引入它的代码放在引入jQuery主文件之后. <he ...

  8. SoapUI调用Web服务

    msg = string.Empty; //string sendAddr, string destAddr, string smContent, int IsNeedreport, DateTime ...

  9. 跨站请求伪造(Cross Site Request Forgery (CSRF))

    跨站请求伪造(Cross Site Request Forgery (CSRF)) 跨站请求伪造(Cross Site Request Forgery (CSRF)) 跨站请求伪造(Cross Sit ...

  10. hdu 3333 Turing Tree(线段树+离散化)

    刚看到是3xian大牛的题就让我菊花一紧,觉着这题肯定各种高端大气上档次,结果果然没让我失望. 刚开始我以为是一个普通的线段树区间求和,然后啪啪啪代码敲完测试没通过,才注意到这个求和是要去掉相同的值的 ...