算法 —— 快速幂

目录

 P1045 [NOIP2003 普及组] 麦森数

P1226 【模板】快速幂

原理I

原理II

P1226 代码解析

P1045 代码解析  


P1045 [NOIP2003 普及组] 麦森数

本题来自洛谷:P1045 [NOIP2003 普及组] 麦森数,根据题意,我们可以看到本题需要计算最少2的1000次方,如果我们要从2的1次方开始计算需要乘二1000次,这无疑是需要消耗大量时间的,在解决本题之前可以先学习一下下面算法:快速幂

P1226 【模板】快速幂

本题来自洛谷:P1226 【模板】快速幂,题目已经告诉你需要使用快速幂算法来解决问题。

根据题解大佬给出的介绍,本蒟蒻对此进行了总结:

很显然,快速幂算法就是为了解决大量乘法次数而产生的,这种算法可以让计算机快速计算出

a^b,暴力相乘的话,电脑要计算 b 次,用快速幂,计算次数在 log(b) 级别。


原理I

先看以下幂运算的特性,相信大家觉得不难:

 了解了这些特性,我们可以利用它来解决问题,过程如下:

  1. 幂与1进行按位与运算
  2. 为1就说明该位对应的二进制存在,需要乘
  3. 为0说明该位对应的二进制不存在,a自乘提升后的值不需要乘

 直接来一个例子给大家更好的认识此过程:

假设我们拿到了 𝑎,并且 𝑏=11。想求 𝑎 ^ 11,但是又不想乘11次,有点慢。以电脑视角稍稍观察一下 𝑏=11,二进制下是 𝑏=1011。

制作一个 𝑏𝑎𝑠𝑒。现在 𝑏𝑎𝑠𝑒=𝑎,表示的是,𝑎 ^ 1 = 𝑎,待会 𝑏𝑎𝑠𝑒会发生改变的。

制作一个 𝑎𝑛𝑠,初值 1,准备用来做答案。

由于11的二进制有4位,所以我们要进行4次循环判断:

1、循环一,看 𝑏 的最后一位是 1 吗? 如果是,代表 a 的一次方存在,以 𝑎𝑛𝑠 ∗= 𝑏𝑎𝑠𝑒。

if(b & 1)ans *= base;/*关于 b & 1:
x & y 是二进制 x 和 y 的每一位分别进行“与运算”的结果。
与运算,即两者都为 1 时才会返回 1,否则返回 0。
那么 b & 1二进制
b     =    1011
1     =    0001
b&1   =    0001因为 1(二进制)的前面几位全部都是 0,
所以只有 b 二进制最后一位是 1 时,b & 1 才会返回 1。*/

 判断完成之后base上升一次(自乘)

base *= base;

同时b最低位就要舍弃掉了,下一次循环用前一位来与1进行按位与运算,舍弃方式直接右移一位。

b >>= 1;

2、循环二,再看看 𝑏,此时b的二进制表示为101,最后一位还是 1,这说明有 a 的二次方存在,我们依旧𝑎𝑛𝑠 ∗= 𝑏𝑎𝑠𝑒(此时base为a的二次方),继续进行上述操作。

3、循环三,继续看看 𝑏,此时b的二进制表示为10,最后一位是0,说明 a 的三次方不存在了,我们不需要让ans *= base,但是base还要继续自乘上升,因为 b 还没变成0,判断条件依旧成立。

4、循环四, 𝑏 此时为1了,按位与后成立,说明有 a 的四次方,依旧𝑎𝑛𝑠 ∗= 𝑏𝑎𝑠𝑒(base此时为a的四次方)b右移一位后变成0,循环结束。

总的来说,如果 𝑏 在二进制上的某一位是 1,我们就把答案乘上对应的 a^(2^n)。代码如下:

int quickPower(int a, int b)//求a的b次方
{int ans = 1, base = a;//ans为答案,base为a^(2^n)while(b > 0)//b是一个变化的二进制数  每次循环右移位变零{//b&1表示b在二进制下最后一位是不是1,如果是:把ans乘上对应的a^(2^n)if(b & 1)ans *= base;base *= base;//base自乘,由a^(2^n)变成a^(2^(n+1))b >>= 1;//位运算,b右移一位}return ans;
}

 可以看到上述代码只需要循环4次就可以求出2的11次方,而用一个变量不断乘2需要11次循环才能实现,这无疑是大大提高了效率


原理II

快速幂有很多种理解方式。从头开始,看以下图片

 可以看到我们凭借幂是否为奇数将3的11次方拆成了好几个小部分,依次运算,那么用代码如何实现呢?先看思路:假设我们以3的11次方为例

第一层循环,𝑏=11,一个奇数。将 3 ^ 11 分解来看,本层只需把 𝑎𝑛𝑠 ∗= 3。那后面的3 ^ 10呢?我们到下一层再搞定。下几层的总目标是让 𝑎𝑛𝑠∗= 3 ^ 10,也就是让 𝑎𝑛𝑠∗=9 ^ 5。来到下一层的是 𝑥 = 3 ∗ 3 = 9 且 𝑏 = 11 / 2 = 5。

第二层循环,几乎独立于第一层存在。𝑏=5,一个奇数。将 9 ^ 5 分解为 9 * 9 ^ 4 来看。本层只需把 𝑎𝑛𝑠∗=9,后面的我们到下一层再搞定。下几层的总目标是让 𝑎𝑛𝑠∗= 9 ^ 4,也就是让 𝑎𝑛𝑠∗=81 ^ 2。于是 𝑥 = 9∗9 = 81  且 𝑏 = 5/2 = 2。

第三层循环,𝑏=2,不是奇数,只把 81 ^ 2 当作 (81 ^ 2) ^ 1。下几层的总目标是让 𝑎𝑛𝑠∗=81^2。于是 𝑥=81∗81=6561,𝑏=2/2=1。

第四层循环,𝑏=1,是奇数。这时候已经不用看成什么分解了,𝑎𝑛𝑠∗=6561 就可完成总目标,b/2 为 0,结束循环。

代码和上面一样,因为 𝑏 & 1 与 𝑏 %  2 == 1 等效。𝑏 /= 2 与 𝑏 >>= 1 等效。

很显然上述思路是一个分治思想,下面附上代码:

int quick_pow(int a, int b) // a为底数  b为幂
{if (b == 1) //最后一层  没办法再分return a;else{int c = quick_pow(a, b / 2);if (b % 2 == 0) // 81^2这种情况return c * c;elsereturn c * c * a; // 3 * ((3^2)^5)}
}

P1226 代码解析

快速幂经常要结合取余运算,这里介绍取余运算有一些好用的性质,包括:

  1. ( A + B ) % b = ( A  % b + B % b ) % b
  2. ( A × B ) %  b = ( ( 𝐴 % 𝑏 ) × ( 𝐵 % 𝑏 ) ) %  𝑏

学习完以上内容,我们尝试解决最开始留下的问题吧,首先是【模板】快速幂的代码解析:

利用上述性质可以解决本题,不要缩短运算时间后就认为问题解决了,试想一下当数据超过了long long的最大值应该如何解决,所以我们在运算时就要着手处理取余操作

#include<bits/stdc++.h>
using namespace std;
//注意本题 a 和 b 都可能为INT_MAX 用int不够
long long quickPower(long long a, long long b, long long c)
{long long ans = 1, base = a;while (b > 0){if (b & 1){ans *= base;ans %= c;  }base *= base;base %= c;b >>= 1;}return ans;
}int main()
{long long a, b, p; cin >> a >> b >> p;cout << a << '^' << b << " mod " << p << '=' << quickPower(a, b, p) << endl;return 0;
}


P1045 代码解析 

#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int f[1001],p,res[1001],sav[1001];//乘法要开两倍长度
void result_1()
{memset(sav,0,sizeof(sav));for(register int i=1;i<=500;i+=1)for(register int j=1;j<=500;j+=1)sav[i+j-1]+=res[i]*f[j];//先计算每一位上的值(不进位)for(register int i=1;i<=500;i+=1){sav[i+1]+=sav[i]/10;//单独处理进位问题,不容易出错sav[i]%=10;}memcpy(res,sav,sizeof(res));//cstring库里的赋值函数,把sav的值赋给res
}
void result_2()//只是在result_1的基础上进行了细微的修改
{memset(sav,0,sizeof(sav));for(register int i=1;i<=500;i+=1)for(register int j=1;j<=500;j+=1)sav[i+j-1]+=f[i]*f[j];for(register int i=1;i<=500;i+=1){sav[i+1]+=sav[i]/10;sav[i]%=10;}memcpy(f,sav,sizeof(f));
}
int main()
{scanf("%d",&p);printf("%d\n",(int)(log10(2)*p+1));res[1]=1;f[1]=2;//高精度赋初值while(p!=0)//快速幂模板{if(p%2==1)result_1();p/=2;result_2();}res[1]-=1;for(register int i=500;i>=1;i-=1)//注意输出格式,50个换一行,第一个不用if(i!=500&&i%50==0)printf("\n%d",res[i]);else printf("%d",res[i]);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/378552.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker的数据管理和网络通信

目录 一、Docker 的数据管理 1&#xff0e;数据卷 2&#xff0e;数据卷容器 二、端口映射 三、容器互联&#xff08;使用centos镜像&#xff09; 四、*Docker 镜像的创建 1&#xff0e;基于现有镜像创建 2&#xff0e;基于本地模板创建 3&#xff0e;基于Dockerfile 创…

SwiftUI中App启动入口分析,以及视图和App生命周期介绍

App入口分析 新创建的swiftui项目中我们应该先要了解一下app的入口函数在哪里,并了解大概的含义。 @main:标记应用程序的入口。 App 协议:SwiftUI 应用程序的入口点。 Scene:表示应用程序的一个视图层级,通常是 WindowGroup,表示主窗口的内容。 Scene讲解 Scene 表示…

线性表的链式存储结构————双链表(java)

线性表的链式存储结构————双链表&#xff08;java&#xff09; 文章目录 线性表的链式存储结构————双链表&#xff08;java&#xff09;双链表双链表的创建插入数据元素头插法尾插法 求链表的长度输出双链表删除双链表中的指定元素总代码运行效果用Java内部类实现双链表…

[HCTF 2018]WarmUp1

进入靶场&#xff0c;检查代码看到有source.php,访问 /source.php 读代码&#xff0c;在参数中传入 file&#xff0c;通过checkFile后&#xff0c;会加载file界面。 再看checkFile&#xff0c; 第一个判断&#xff0c;是非空并且是个字符串&#xff0c;否则返回false 第二个判…

小程序里面使用vant ui中的vant-field组件,如何使得输入框自动获取焦点

//.wxml <van-fieldmodel:value"{{ userName }}"placeholder"请输入学号"focus"{{focusUserName}}"/>// .js this.setData({focusUserName: true});vant-field

华为OD算法题汇总

60、计算网络信号 题目 网络信号经过传递会逐层衰减&#xff0c;且遇到阻隔物无法直接穿透&#xff0c;在此情况下需要计算某个位置的网络信号值。注意:网络信号可以绕过阻隔物 array[m][n]&#xff0c;二维数组代表网格地图 array[i][j]0&#xff0c;代表i行j列是空旷位置 a…

快捷:通过胶水语言实现工作中测试流程并行、加速

通过胶水语言实现工作中测试流程并行、加速 通过胶水语言实现工作中测试流程并行、加速工作场景&#xff08;背景&#xff09;问题抽象&#xff08;挑战&#xff09;如何做&#xff08;行动&#xff09;获得了什么&#xff08;结果&#xff09;后记相关资源 通过胶水语言实现工…

唐刘:当 SaaS 爱上 TiDB(一)- 行业挑战与 TiDB 的应对之道

导读 在 TiDB 8.1 发布后&#xff0c;TiDB 展现了强大的支持 SaaS 业务的能力&#xff0c;成为 SaaS 业务数据库的优先选择之一。 本文为“当 SaaS 爱上 TiDB”系列文章的第一篇&#xff0c;系列文章将从技术原理和真实用户体验两个角度深入探讨 TiDB 在 SaaS 业务中的表现&a…

qt 创建一个左侧边线拖拽的矩形

1.概要 2.代码 在Qt中&#xff0c;如果你想要创建一个矩形&#xff0c;并且仅允许通过拖拽其左侧边线来改变宽度&#xff0c;你可以通过重写QGraphicsRectItem类来实现。以下是一个简单的例子&#xff0c;展示了如何创建一个自定义的ResizableRectItem类&#xff0c;该类允许…

责任链模式+CompletableFuture异步处理

1、查询商品基础信息 2、查询商品价格 3、查询商品活动 4、查询商品库存 假设这几个服务逻辑比较独立&#xff0c;其实是可以并行调用&#xff0c;我们可以结合责任链模式和CompletableFuture进行优化: 下面是代码示例: Service public class ChainFactory {// 原型模式获取对…

GloVe: Global Vectors for Word Representation论文笔记解读

基本信息 作者Jeffrey Penningtondoi10.3115/v1/D14-1162发表时间2014期刊EMNLP网址https://aclanthology.org/D14-1162.pdf 研究背景 1. What’s known 既往研究已证实 全局矩阵分解方法&#xff1a;LSA&#xff0c;考虑整个语料库词频的统计信息得到共现矩阵&#xff0c;通…

Spring Security学习笔记(一)Spring Security架构原理

前言&#xff1a;本系列博客基于Spring Boot 2.6.x依赖的Spring Security5.6.x版本 Spring Security中文文档&#xff1a;https://springdoc.cn/spring-security/index.html 一、什么是Spring Security Spring Security是一个安全控制相关的java框架&#xff0c;它提供了一套全…

昇思25天学习打卡营第1天 | 基本介绍

打卡&#xff1a; 小白一个&#xff0c;第一次接触昇思MindSpore&#xff0c;之前使用chatgpt较多一点。这次相当于从使用着角色转换成制作者的角色&#xff0c;跨度比较大。如果之前没有接触过相关内容&#xff0c;学习起来还是比较费劲。 基本介绍&#xff1a; 昇思MindSpo…

ValueError和KeyError: ‘bluegrass’的问题解决

项目场景&#xff1a; 项目相关背景&#xff1a; 问题描述 遇到的问题1&#xff1a; KeyError: ‘bluegrass’ 不能识别某标签 遇到的问题2&#xff1a; xml etree.fromstring(xml_str) ValueError: Unicode strings with encoding declaration are not supported. Please …

K8S 中的 CRI、OCI、CRI shim、containerd

K8S 如何创建容器&#xff1f; 下面这张图&#xff0c;就是经典的 K8S 创建容器的步骤&#xff0c;可以说是冗长复杂&#xff0c;至于为什么设计成这样的架构&#xff0c;继续往下读。 前半部分 CRI&#xff08;Container Runtime Interface&#xff0c;容器运行时接口&#xf…

PCIe驱动开发(3)— 驱动设备文件的创建与操作

PCIe驱动开发&#xff08;3&#xff09;— 驱动设备文件的创建与操作 一、前言 在 Linux 中一切皆为文件&#xff0c;驱动加载成功以后会在“/dev”目录下生成一个相应的文件&#xff0c;应用程序通过对这个名为“/dev/xxx” (xxx 是具体的驱动文件名字)的文件进行相应的操作即…

元宇宙深入解析

元宇宙&#xff08;Metaverse&#xff09;是一个新兴的概念&#xff0c;它激发了技术专家、艺术家和商业领袖的无限想象。它代表着数字互动的新前沿&#xff0c;提供了一个平行的数字宇宙&#xff0c;用户可以在其中实时互动&#xff0c;超越物理世界的限制。 元宇宙是什么&am…

安防视频监控/视频汇聚EasyCVR平台浏览器http可以播放,https不能播放,如何解决?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台基于云边端一体化架构&#xff0c;兼容性强、支持多协议接入&#xff0c;包括国标GB/T 28181协议、部标JT808、GA/T 1400协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为SDK、宇视SDK、乐橙SDK、萤石云SD…

链接追踪系列-00.es设置日志保存7天-番外篇

索引生命周期策略 ELK日志我们一般都是按天存储&#xff0c;例如索引名为"zipkin-span-2023-03-24"&#xff0c;因为日志量所占的存储是非常大的&#xff0c;我们不能一直保存&#xff0c;而是要定期清理旧的&#xff0c;这里就以保留7天日志为例。 自动清理7天以前…

Python基础语法篇(上)

Python基础语法&#xff08;上&#xff09; 一、基知二、基本数据类型&#xff08;一&#xff09;标准数据类型&#xff08;二&#xff09;数据类型转换 三、字符串基本操作&#xff08;一&#xff09;字符串的索引和切片&#xff08;二&#xff09;字符串的拼接 三、运算符四、…