目录

快速幂

快速幂取模

矩阵快速幂

矩阵快速幂取模

[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. mpvue 小程序开发之 数据埋点统计

    mpvue 小程序开发之 数据埋点统计 在开发过程中,有数据统计的需求,需要获取小程序当前页面和来源页面的数据,以及页面的停留时间 在对小程序api进行了一番研究之后,发现获取这些数据其实并不难 当前 ...

  2. js计算数组中元素出现的次数,并实现去重

    function getCount(arr, rank,ranktype){ var obj = {}, k, arr1 = []; for (var i = 0, len = arr.length; ...

  3. Qt TCP通信

    工程文件 QT += network 服务端 #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QTcpS ...

  4. 网络编程(四)--基于udp协议的套接字、socketserver模块

    一.UDP协议(数据报协议) 1.何为udp协议 不可靠传输,”报头”部分一共只有8个字节,总长度不超过65,535字节,正好放进一个IP数据包. 以太网头 ip头                  ...

  5. python调用函数设置超时机制

    有时候需要给函数设置超时机制,以防止它卡住我们的程序,这里可以用python的signal模块,signal模块可以实现程序内部的信号处理. # coding:utf8 import time imp ...

  6. docker上启动mysql镜像,mysq中记录乱码解决方法

    在docker上启动一个mysql, 1. docker pull mysql 2. docker run --name mysql_dev -p 3306:3306 -e MYSQL_ROOT_PA ...

  7. Ubuntu 开发环境搭建教程

    Ubuntu 开发环境搭建教程 本文原始地址:https://sitoi.cn/posts/18425.html 更新 sudo apt upgrade sudo apt update 生成本机密钥 ...

  8. springboot日常问题处理手记

    springboot启动问题 1.@Autowired报错Could not autowire. No beans of xxx 解决:只需在DAO接口加上@Component 或者 @Reposit ...

  9. 前端性能优化 http请求的过程及潜在的优化点

    CS架构:比如我们的代码开发好,打包成apk,发布到平台,那么最终怎么运行到用户的手机上呢,用户首先需要从相关的应用商城下载这个apk包,并且运行这个 apk 包,那么这个 apk 包就会被解压,最后 ...

  10. 201871010126 王亚涛 《面向对象程序设计(java)》 第二周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...