目录

快速幂

快速幂取模

矩阵快速幂

矩阵快速幂取模

[HDU1005练习](#Number Sequence)

快速幂

幂运算:\(x ^ n\)

​ 根据其一般定义我们可以简单实现其非负整数情况下的函数

定义法:

int Pow (int x, int n) {
int result = 1; while(n--) {
result *= x;
} return result;
}

​ 不难看出此时算法的时间复杂度是\(O(n)\),一旦n取较大数值,计算时间就会大大增加,极其容易出现超时的情况。

快速幂:

​ 首先要在此列举两个前提:

  1. 计算机是通过二进制进行存储数据的,对二进制数据可以直接进行操作。

  2. \(2^n+2^n=2*2^n=2^{n + 1}\)

​ 对于\(x ^ n\),其中n可以表示为m位的二进制形式,即\(n=n_12^0+n_22^1+n_32^3+\cdots+n_m2^{m-1}\)

​ 那么\(x ^ n=x ^ {n_12^0+n_22^1+n_32^3+\cdots+n_m2^{m-1}}\)

​ 即\(x^n=x ^ {n_12^0}x^{n_22^1}x^{n_32^3}\cdots x^{n_m2^{m-1}}\)

​ 根据前提1,计算机可以直接对二进制格式存储的数据进行读取,那么我们就可以对\(n\)一个个读取再对其进行累乘。

​ 当取到第\(a\)位时,其乘数有通项公式:\(x^{n_a2^{a-1}}\)

​ 通过标准库math,用代码实现:

int Pow (int x, int n) {

    int result = 1;

    int a = 1;

    while(n) {
if(n & 1) result *= round( pow(x, 1 << (a - 1)) );//round的作用在于double转int时防止丢失精度,对1进行位运算是一种计算2的n次幂的快速方法
n >>= 1; a++;
} return result;
}

但实际上这个调用了标准库的代码并没有实现快速幂,因为仍然是采用pow()进行的运算

此处由 \(2^n+2^n=2\times2^n=2^{n + 1}\)

即\((x ^ {2 ^ {n}} )^2=x ^ {2\times 2 ^ {n}} =x ^ {2 ^ {n + 1}}\)

因此我们可以通过对前项进行二次幂运算得到后项

先得到首项\(f(1)=x^{2^{1-1}}=x\)

即令int f = x

具体实现:

int Pow (int x, int n) {

    int result = 1;

    int f = x;

    while(n) {
if(n & 1) result *= f; f *= f; n >>= 1;
} return result;
}

不难发现此时算法的时间复杂度由其次数的二进制位数而决定,即\(O(m)\)也就是\(O(log_2n)\)

另外因为此算法常常用于计算大数,所以int类型最好都换成long long类型,防止溢出。

快速幂取模

​ 对\(x^n\)取模运算:\(x^n\mod p\),当n极大时,同样其运算量也会增大

​ 这就需要我们寻求一种快速解决的方法,此时可以运用我们上文所提到的快速幂算法

​ 引论1:\((np+a)\mod p=a\mod p\quad (n\in\mathbb{Z} )\)

​ 证明如下:设\(f(n,p,a)=(np+a)\mod p\quad (n\in\mathbb{Z} )\)

​ 则由定义有\((np+a)\mod p\\=\frac{np+d}{p}-([\frac{np+d}{p}+1]-1)\\ =d-p([\frac{d}{p}+1]-1)\)

​ 显而易见,\((np+a)\mod p=a\)与\(n\)无关

​ 令\(n=0\)得\((np+a)\mod p=a\mod p\quad (n\in\mathbb{Z} )\\ Q.E.D\)

​ 引论2:\((mn)\mod p=((m\mod p)(n\mod p))\mod p\)

​ 证明如下:令\(\left\{ \begin{array}{c} m=(ip+c)& (i\in\mathbb{Z} )\\ n=(jp+d) & (j\in\mathbb{Z} )\end{array} \right.\)

​ 则有\(\left\{ \begin{array}{c} m\mod p=c\\ n\mod p=d \end{array} \right.\)

​ 原式\((m*n)%p\\=((ip+c)(jp+d))\mod p\\=(jip^2+jpc+ipd+cd)\mod p\\=(jip^2+jpc+ipd+cd)\mod p\\=((jip+jc+id)p+cd)\mod p\\因为(jip+jc+id)\in\mathbb{Z},由引论1得:\\=(cd)\mod p\\=((m\mod p)(n\mod p))\mod p\)

​ 即\((mn)\mod p=((m\mod p)(n\mod p))\mod p\\ Q.E.D\)

​ 因此对于\(x^n\mod p\)

​ 可以写成\((x ^ {n_12^0}x^{n_22^1}x^{n_32^3}\cdots x^{n_m2^{m-1}})\mod p\\ =((x ^ {n_12^0}\mod p)(x^{n_22^1}\mod p)(x^{n_32^3}\mod p)\cdots (x^{n_m2^{m-1}}\mod p))\mod p\)

​ 并且由之前的推定\((x ^ {2 ^ {n}} )^2=x ^ {2\times 2 ^ {n}} =x ^ {2 ^ {n + 1}}\)

​ 有\((x ^ {2 ^ {n}} \mod p)^2\mod p =(x ^ {2 ^ {n}})^2\mod p=x ^ {2 ^ {n + 1}}\mod p\)

​ 代码实现:

int Mod (int x, int n, int p) {

    int result = 1;

    int f = x % p;

    while(n) {
if(n & 1) result = (result * f)%p; f = (f * f)%p; n >>= 1;
} return result;
}

矩阵快速幂

​ 当\(X\)为任意方块矩阵,即\(X=\left| \begin{matrix} x_{11} & \cdots & x_{1n}\\ \vdots & \ddots & \vdots \\ x_{n1} & \cdots & x_{nn}\\ \end{matrix} \right|\)时

​ 同理\(X^a\),有\(X^a=X ^ {a_12^0}X^{a_22^1}X^{a_32^3}\cdots X^{a_m2^{m-1}}\)

​ 同样的,任意方块矩阵也适用于快速幂

​ 代码实现:

#include <iostream>
#include <cstring> using namespace std; #define R 2 struct Matrix{
int data[R][R];
}; Matrix multi(Matrix a,Matrix b,int rec){ Matrix result; memset(&(result.data), 0, sizeof(result.data)); for(int i = 0; i < rec; i++)
for(int j = 0; j < rec; j++)
for(int k = 0; k < rec; k++)
result.data[i][j] += a.data[i][k] * b.data[k][j]; return result;
} Matrix poww (Matrix x, int n) { Matrix result; memset(&(result.data), 0,sizeof( result.data)); for(int i = 0; i < R; i++) result.data[i][i] = 1; Matrix f = x; while(n) {
if(n & 1) result = multi(result, f, R); f = multi(f, f, R); n >>= 1;
} return result;
} void MatrixPrint(Matrix target) { for(int i = 0; i < R; i++) { for(int j = 0; j < R; j++) cout << target.data[i][j]<< " "; cout << endl; } } int main() { Matrix result; memset(&(result.data), 0,sizeof( result.data)); result.data[0][0] = 1; result.data[0][1] = 2; result.data[1][0] = 3; result.data[1][1] = 4; MatrixPrint(result); cout << endl; result = poww(result, 3); MatrixPrint(result); return 0;
}

输出结果:

1 2

3 4

37 54

81 118

矩阵快速幂取模

​ 运算定义:当\(X\)为任意方块矩阵,即\(X=\left| \begin{matrix} x_{11} & \cdots & x_{1n}\\ \vdots & \ddots & \vdots \\ x_{n1} & \cdots & x_{nn}\\ \end{matrix} \right|\)时

​ 则\(X\mod p=\left| \begin{matrix} x_{11} \mod p & \cdots & x_{1n}\mod p\\ \vdots & \ddots & \vdots \\ x_{n1}\mod p & \cdots & x_{nn}\mod p\\ \end{matrix} \right|\)

​ 引论1:\((m+n)\mod p=((m\mod p)+(n\mod p))\mod p\)

​ 证明如下:令\(\left\{ \begin{array}{c} m=(ip+c)& (i\in\mathbb{Z} )\\ n=(jp+d) & (j\in\mathbb{Z} )\end{array} \right.\)

​ 则有\(\left\{ \begin{array}{c} m \mod p=c\\ n \mod p=d \end{array} \right.\)

​ 原式\((m+n)\mod p\\=((ip+c)+(jp+d))\mod p\\=((i+j)p+c+d)\mod p\\因为(i+j)\in\mathbb{Z},由上文引论得:\\=(c+d)\mod p\\=((m\mod p)+(n\mod p))\mod p\)

​ 即\((m+n)\mod p=((m\mod p)+(n\mod p))\mod p\\ Q.E.D\)

​ 引论2:有方块矩阵\(X=\left| \begin{matrix} x_{11} & \cdots & x_{1n}\\ \vdots & \ddots & \vdots \\ x_{nn} & \cdots & x_{nn}\\ \end{matrix} \right|\),\(Y=\left| \begin{matrix} y_{11} & \cdots & y_{1m}\\ \vdots & \ddots & \vdots \\ y_{n1} & \cdots & y_{nm}\\ \end{matrix} \right|\)

​ 则有\(XY\mod p=((X\mod p)·(Y\mod p))\mod p\)

​ 证明如下:

​ 令\(X=\left| \begin{matrix} x_{11} & \cdots & x_{1n}\\ \vdots & \ddots & \vdots \\ x_{n1} & \cdots & x_{nn}\\ \end{matrix} \right|\),\(Y=\left| \begin{matrix} y_{11} & \cdots & y_{1n}\\ \vdots & \ddots & \vdots \\ y_{n1} & \cdots & y_{nn}\\ \end{matrix} \right|\)

​ 则

\(X·Y\mod p=\left| \begin{matrix} (x_{11}y_{11} + \cdots +x_{1n}y_{n1})\mod p & \cdots & (x_{11}y_{1n} + \cdots +x_{1n}y_{nn})\mod p\\ \vdots & \ddots & \vdots \\ (x_{n1}y_{11} + \cdots +x_{nn}y_{n1})\mod p & \cdots & (x_{n1}y_{1n} + \cdots +x_{nn}y_{nn})\mod p\\ \end{matrix} \right|\)

\(=\left| \begin{matrix} ((x_{11}y_{11})\mod p + \cdots +(x_{1n}y_{n1})\mod p )\mod p & \cdots & ((x_{11}y_{1n})\mod p + \cdots +(x_{1n}y_{nn})\mod p\mod p\\ \vdots & \ddots & \vdots \\ ((x_{n1}y_{11})\mod p + \cdots +(x_{nn}y_{n1})\mod p)\mod p & \cdots & ((x_{n1}y_{1n})\mod p + \cdots +(x_{nn}y_{nn})\mod p)\mod p\\ \end{matrix} \right|\)

\(=\left| \begin{matrix} (((x_{11}\mod p)(y_{11}\mod p))\mod p + \cdots +((x_{1n}\mod p)(y_{n1}\mod p))\mod p )\mod p & \cdots & (((x_{11}\mod p)(y_{1n}\mod p))\mod p + \cdots +(((x_{1n}\mod p)(y_{nn}\mod p))\mod p)\mod p\\ \vdots & \ddots & \vdots \\ (((x_{n1}\mod p)(y_{11}\mod p))\mod p + \cdots +((x_{nn}\mod p)(y_{n1}\mod p))\mod p)\mod p & \cdots & (((x_{n1}\mod p)(y_{1n}\mod p))\mod p + \cdots +((x_{nn}\mod p)(y_{nn}\mod p))\mod p)\mod p\\ \end{matrix} \right|\)

\(=\left| \begin{matrix} ((x_{11}\mod p)(y_{11}\mod p) + \cdots +(x_{1n}\mod p)(y_{n1}\mod p))\mod p & \cdots & ((x_{11}\mod p)(y_{1n}\mod p) + \cdots +((x_{1n}\mod p)(y_{nn}\mod p))\mod p\\ \vdots & \ddots & \vdots \\ ((x_{n1}\mod p)(y_{11}\mod p) + \cdots +(x_{nn}\mod p)(y_{n1}\mod p))\mod p & \cdots & ((x_{n1}\mod p)(y_{1n}\mod p) + \cdots +(x_{nn}\mod p)(y_{nn}\mod p))\mod p\\ \end{matrix} \right|\)

\(=\left( \left| \begin{matrix} x_{11}\mod p & \cdots & x_{1n}\mod p\\ \vdots & \ddots & \vdots \\ x_{n1}\mod p & \cdots & x_{nn}\mod p\\ \end{matrix} \right|\left| \begin{matrix} y_{11}\mod p & \cdots & y_{1n}\mod p\\ \vdots & \ddots & \vdots \\ y_{n1}\mod p & \cdots & y_{nn}\mod p\\ \end{matrix} \right| \right)\mod p\)

\(=((X\mod p)·(Y\mod p))\mod p \\\text{即}XY\mod p=((X\mod p)·(Y\mod p))\mod p\\Q.E.D\)

说明任意矩阵也符合快速幂取模的算法

具体实现:

#include <iostream>
#include <cstring> using namespace std; #define R 2 struct Matrix{
int data[R][R];
}; Matrix multi(Matrix a,Matrix b,int rec,int p){ Matrix result; memset(&(result.data), 0,sizeof( result.data)); for(int i = 0; i < rec; i++)
for(int j = 0; j < rec; j++) { for(int k = 0; k < rec; k++)
result.data[i][j] += a.data[i][k] * b.data[k][j]; result.data[i][j] %= p; } return result;
} Matrix poww (Matrix x, int n, int p) { Matrix result; memset(&(result.data), 0,sizeof( result.data)); for(int i = 0; i < R; i++) result.data[i][i] = 1; Matrix f = x; while(n) {
if(n & 1) result = multi(result, f, R, p); f = multi(f, f, R, p); n >>= 1;
} return result;
} void MatrixPrint(Matrix target) { for(int i = 0; i < R; i++) { for(int j = 0; j < R; j++) cout << target.data[i][j]<< " "; cout << endl; } } int main() { Matrix result; memset(&(result.data), 0,sizeof( result.data)); result.data[0][0] = 1; result.data[0][1] = 2; result.data[1][0] = 3; result.data[1][1] = 4; MatrixPrint(result); cout << endl; result = poww(result, 3, 3); MatrixPrint(result); return 0;
}

输出结果:

1 2

3 4

1 0

0 1

练习(HDU1005):

Number Sequence

Problem Description

A number sequence is defined as follows:

\(f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) \mod 7.\)

Given A, B, and n, you are to calculate the value of f(n).

Input

The input consists of multiple test cases. Each test case contains 3 integers A, B and n on a single line (1 <= A, B <= 1000, 1 <= n <= 100,000,000). Three zeros signal the end of input and this test case is not to be processed.

Output

For each test case, print the value of f(n) on a single line.

Sample Input

1 1 3

1 2 10

0 0 0

Sample Output

2

5

Author

CHEN, Shunbao

Source

ZJCPC2004

​ 由题意不难发现,题目输入三个数A,B,n,要求我们求出广义的斐波那契数列(generalized Fibonacci sequence)第n项的取模

​ 即\(f(n) = (A * f(n - 1) + B * f(n - 2)) \mod 7 = (Aa_{n-1}+Ba_{n-2})= a_n \mod 7\)

​ 因此通过前后项关系,可以构建矩阵\(\left| \begin{matrix} a_{n} & 0\\ a_{n-1} & 0\\ \end{matrix} \right|\mod 7=\left( \left| \begin{matrix} A & B\\ 1 & 0\\ \end{matrix} \right|\left| \begin{matrix} a_{n-1} & 0\\ a_{n-2} & 0\\ \end{matrix} \right| \right)\mod 7\)

\(=\left( \left| \begin{matrix} A & B\\ 1 & 0\\ \end{matrix} \right|^{n-2}\left| \begin{matrix} a_2 & 0\\ a_1 & 0\\ \end{matrix} \right| \right)\mod 7\)

\(=\left(\left( \left| \begin{matrix} A & B\\ 1 & 0\\ \end{matrix} \right|^{n-2}\mod 7\right)\left(\left| \begin{matrix} a_2 & 0\\ a_1 & 0\\ \end{matrix} \right|\mod7\right) \right)\mod 7\)

如此,就转化为一个矩阵快速幂的问题

具体实现(谢谢提醒!原来我的solution忽略了\(n = 1\)和\(n = 2\)的情况,导致无限循环):

#include <iostream>
#include <cstring> using namespace std; #define R 2 struct M{
int data[R][R];
}; M multi(M a,M b,int rec,int p){ M result; memset(&(result.data), 0,sizeof( result.data)); for(int i = 0; i < rec; i++)
for(int j = 0; j < rec; j++) { for(int k = 0; k < rec; k++)
result.data[i][j] += a.data[i][k] * b.data[k][j]; result.data[i][j] %= p; } return result;
} M poww (M x, int n, int p) { M result; M f = x; memset(&(result.data), 0,sizeof( result.data)); for(int i = 0; i < R; i++) result.data[i][i] = 1; while(n) { if(n & 1) result = multi(result, f, R, p); f = multi(f, f, R, p); n >>= 1; } return result;
} M solve(int a, int b, int n, int p) { M result; M trans; memset(&(result.data), 0,sizeof( result.data)); memset(&(trans.data), 0,sizeof( trans.data)); result.data[0][0] = 1; result.data[1][0] = 1; trans.data[0][0] = a; trans.data[0][1] = b; trans.data[1][0] = 1; trans = poww(trans, n, p); result = multi(trans, result, R, p); return result; } int main() { int a, b, n; while(true) { cin >> a >> b >> n; if(!a && !b && !n) break; if(n == 2 || n == 1 ){ cout << 1 << endl; continue;
} cout << solve(a, b, n - 2, 7).data[0][0] << endl; } return 0;
}

ACM | 算法 | 快速幂的更多相关文章

  1. ACM数论-快速幂

    ACM数论——快速幂 快速幂定义: 顾名思义,快速幂就是快速算底数的n次幂.其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高. 原理: 以下以求a的b次方来介绍: 把b转换成 ...

  2. Java 算法-快速幂

    1 什么是快速幂? 快速幂,顾名思义就是快速的求次幂,例如:a^b,普通的算法就是累乘,这样的计算方法的时间复杂度就是O(n),而快速幂的方法使得次幂的计算方法的时间复杂度降低到O(logn).  假 ...

  3. Python经典算法-快速幂

    快速幂 问题描述: 计算a ** n % b 其中a.b和n都是32位的非负整数 即求a的n次方对b的余数 问题示例: 例如:2**31%3=2 --- 代码实现如下 class Solution: ...

  4. [每日一题2020.06.15]P1226 【模板】快速幂取余运算

    我是题目 快速幂就是快速求 \(a^b\)的一种算法 快速幂 思想 : 比如我要求 \(6^9\) 首先将幂转化为二进制形式 : \[6^9 = 6^{1001} \tag{1} \] 可以得到 : ...

  5. 整数快速乘法/快速幂+矩阵快速幂+Strassen算法

    快速幂算法可以说是ACM一类竞赛中必不可少,并且也是非常基础的一类算法,鉴于我一直学的比较零散,所以今天用这个帖子总结一下 快速乘法通常有两类应用:一.整数的运算,计算(a*b) mod c  二.矩 ...

  6. 矩阵快速幂在ACM中的应用

    矩阵快速幂在ACM中的应用 16计算机2黄睿博 首发于个人博客http://www.cnblogs.com/BobHuang/ 作为一个acmer,矩阵在这个算法竞赛中还是蛮多的,一个优秀的算法可以影 ...

  7. 华东交通大学2018年ACM“双基”程序设计竞赛 C. 公式题 (2) (矩阵快速幂)

    题目链接:公式题 (2) 比赛链接:华东交通大学2018年ACM"双基"程序设计竞赛 题目描述 令f(n)=2f(n-1)+3f(n-2)+n,f(1)=1,f(2)=2 令g(n ...

  8. 【转】C语言快速幂取模算法小结

    (转自:http://www.jb51.net/article/54947.htm) 本文实例汇总了C语言实现的快速幂取模算法,是比较常见的算法.分享给大家供大家参考之用.具体如下: 首先,所谓的快速 ...

  9. Raising Modulo Numbers_快速幂取模算法

    Description People are different. Some secretly read magazines full of interesting girls' pictures, ...

随机推荐

  1. kingbase常用语句

    1. 查询数据库名 # select * from SYS_DATABASE; 2. 查询模式名 # select * from SYS_NAMESPACE; 3. 查询表空间 # select * ...

  2. 【计算机网络】windows修改本机hosts文件

    hosts 文件所在的位置 C:/windows/system32/drivers/etc/hosts 修改后不必重启立即生效的方法 命令行下运行: ipconfig /displaydns 显示所有 ...

  3. centos6升级python版本至python3.5

    一. 从Python官网到获取Python3的包, 切换到目录/usr/local/src wget https://www.python.org/ftp/python/3.5.1/Python-3. ...

  4. 让天堂的归天堂,让尘土的归尘土——谈Linux的总线、设备、驱动模型

    本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 公元1951年5月15日的国会听证上, ...

  5. js 驼峰命名和下划线互换

    代码走你 // 下划线转换驼峰 function toHump(name) { return name.replace(/\_(\w)/g, function(all, letter){ return ...

  6. 201671010402-陈靖 实验十四 团队项目评审&课程学习总结

    项目 内容 任课教师博客主页链接 https://www.cnblogs.com/nwnu-daizh/ 作业要求链接地址 https://www.cnblogs.com/nwnu-daizh/p/1 ...

  7. am instrument 命令详解运行多个用例

    1 Instrument是什么? instrument为am命令的一个子命令.用于启动一个Instrumentation测试.首先连接手机或者模拟器,通过adb shell命令,进入shell层进行操 ...

  8. css做的艺术字效果

    Arctext.js 转自  http://tympanus.net/Development/Arctext/

  9. 树莓派搭建基于flask的web服务器-通过移动端控制LED

    1.概述 在局域网内,基于flask搭建web服务,从而可以使用移动客户端访问该web服务.由于是flask新手,所以本次实现的web服务功能较为简单,即控制LED灯的开/关及闪烁. 2.准备工作 2 ...

  10. Flex弹性盒模型(新老版本完整)--移动端开发整理笔记(二)

    Flex布局 Flex即Flexible Box,写法为:display:flex(旧版:display: -webkit-box) 在Webkit内核下,需要加-webkit前缀: .box{ di ...