算法 —— 快速幂

news2024/9/23 3:21:40

目录

 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;
		else
			return 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.coloradmin.cn/o/1930062.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】权限的管理和Linux上的一些工具

文章目录 权限管理chgrpchownumaskfile指令sudo指令 目录权限粘滞位Linux中的工具1.软件包管理器yum2.rzsz Linux开发工具vim 总结 权限管理 chgrp 功能&#xff1a;修改文件或目录的所属组 格式&#xff1a;chgrp [参数] 用户组名 文件名 常用选项&#xff1a;-R 递归修改文…

Host碰撞实验

目录 Host碰撞原理 Host碰撞判断技巧 Host碰撞检测方法 Host碰撞实验步骤 从攻击者的视角来进行资产的梳理&#xff0c;采用全端口扫描子域名收集的方式&#xff0c;识别所有的企业资产暴露面。但即使是这样&#xff0c;往往会因为配置错误或是未及时回收等原因&#xff0c…

android13 frameworks里面常用的保存信息或者版本判断的方法

总纲 android13 rom 开发总纲说明 目录 1.前言 2. 数据库 2.1 代码读取用法参考 3.prop 属性配置 3.1 property的key值有哪些特点 4.区别 5. 其他数据存储 6.彩蛋 1.前言 frameworks 不像我们一般开发app那样,很多应用保存的方法都无法使用。这里记录我们系统rom开…

初学SpringMVC之 JSON 篇

JSON&#xff08;JavaScript Object Notation&#xff0c;JS 对象标记&#xff09;是一种轻量级的数据交换格式 采用完全独立于编程语言的文本格式来存储和表示数据 JSON 键值对是用来保存 JavaScript 对象的一种方式 比如&#xff1a;{"name": "张三"}…

ssh -D 选项用于动态(Dynamic)端口转发

举例实现不同ssh连接功能目录 一、功能简介 -D 支持 SOCKS5 协议&#xff0c;可以同时转发 TCP 和 UDP 报文 二、原理介绍 假设拥有三台主机&#xff0c;具体环境如下&#xff1a; 1. 主机 A&#xff1a;本地主机&#xff0c;即 SSH 客户 所在的主机&#xff0c;IP&#xff1…

Python游戏开发——天天酷跑(完整版教程)只需要200行代码就做出了一个天天酷跑小游戏,原来代码做游戏这么简单!零基础也能教你学会!

最近一段时间&#xff0c;小编发现已经好久没有给大家带来趣味游戏的案例展示了。刚好小编趁着周末写了一个《天天酷跑》的游戏&#xff0c;因此拿来跟大家一起分享&#xff0c;和大家一起来重温经典的酷跑游戏。 01 准备开发环境 俗话说&#xff0c;“工欲善其事&#xff0c…

详解:动画专业就业前景和就业方向

随着数字创意产业的蓬勃发展&#xff0c;动画专业已成为越来越多学子的选择。动画专业的就业前景日益广阔&#xff0c;不仅在游戏、影视、广告等传统领域有着广泛应用&#xff0c;还在建筑、教育、医学等多个行业展现出强大的潜力。 那么&#xff0c;何为动画专业呢&#xff1f…

快慢指针的应用(题目来源力扣oj训练)

快慢指针 快慢指针一般用来找到链表的中间节点&#xff0c;就是直接搞两个指针&#xff0c;快指针的移动是慢指针的两倍&#xff0c;那么为什么快慢指针可以找到中间节点&#xff0c;因为假设一个为n的链表&#xff0c;快指针走完慢指针也就是n/2。 具体案例 找链表的中间节…

【深度学习入门篇 ⑦】PyTorch池化层

【&#x1f34a;易编橙&#xff1a;一个帮助编程小伙伴少走弯路的终身成长社群&#x1f34a;】 大家好&#xff0c;我是小森( &#xfe61;ˆoˆ&#xfe61; ) &#xff01; 易编橙终身成长社群创始团队嘉宾&#xff0c;橙似锦计划领衔成员、阿里云专家博主、腾讯云内容共创官…

Windows 系统利用 SSH 和 WSL2 子系统当服务器

由于最近组内需要将一台 Windows 系统的电脑 W A W_A WA​ 转成能通过 SSH 访问&#xff0c;并且能用 Linux 命令当服务器运行。忙活了一天&#xff0c;终于是把全部东西弄通了。 安装 SSH 首先就是 W A W_A WA​ 先要安装 OpenSSH 服务&#xff0c;直接按照下面的教程安装…

LVS+Keepalive高可用

1、keepalive 调度器的高可用 vip地址主备之间的切换&#xff0c;主在工作时&#xff0c;vip地址只在主上&#xff0c;vip漂移到备服务器。 在主备的优先级不变的情况下&#xff0c;主恢复工作&#xff0c;vip会飘回到住服务器 1、配优先级 2、配置vip和真实服务器 3、主…

【Python实战因果推断】38_双重差分9

目录 Doubly Robust Diff-in-Diff Propensity Score Model Delta Outcome Model All Together Now Doubly Robust Diff-in-Diff 另一种纳入干预前协变变量和时间不变协变变量以考虑条件平行趋势的方法是制作双稳健差分法&#xff08;DRDID&#xff09;。要做到这一点&#…

鸿蒙语言基础类库:【@system.brightness (屏幕亮度)】

屏幕亮度 说明&#xff1a; 从API Version 7 开始&#xff0c;该接口不再维护&#xff0c;推荐使用新接口[ohos.brightness]。本模块首批接口从API version 3开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import brightness from sy…

【接口自动化_13课_接口自动化总结】

一、自我介绍 二、项目介绍 自己的职责、项目流程 1&#xff09;功能测试&#xff0c;怎么设计用例的--测试策略 2&#xff09;功能测试为什么还有代码实现&#xff0c;能用工具实现&#xff0c;为什么还用代码实现。 基本情况 项目名称:项目类型&#xff1a;项目测试人员…

ubantu22.04安装OceanBase 数据库

1、管理员启动cmd,运行 sudo bash -c "$(curl -s https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/download-center/opensource/service/installer.sh)" 2、提示如下代表安装完成 3、修改数据库配置文件的密码 sudo vim /etc/oceanbase.cnf 然后保存退…

如何申请自费访问学者?自费访问学者材料要哪些?

四、申请自费访问学者需要准备哪些材料 访问学者的申请材料应包括个人简历、推荐信、成绩单、研究计划或课题、语言能力证明等&#xff0c;资费访问学者需提交财务证明。 申请表格填写基本个人信息、访学时间、访学目的等。且应在个人简历详细列出教育背景、工作经历、学术成…

一张图生成绘画全过程,这下人人都成“原画师”了

玩过SD的应该都知道ControlNet吧&#xff0c;最近ControlNet的作者Lvmin Zhang 又搞了一个开源项目PaintsUndo&#xff0c;在Github刚上线就收获了2.7k Star。 只需要上传一张静态图像&#xff0c;PaintsUndo就可以根据提供的图像自动生成对应的绘画全过程视频。 展示从一张白…

【python报错已解决】Stack Overflow

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引言 在开发的旅程中&#xff0c;我们难免会遇到各种各样的报错信息&#xff0c;这些报错就像旅途中的绊脚石&#xff0c;阻挡…

GA-Kmeans-Transformer-GRU时序聚类+状态识别组合模型,创新发文无忧!

GA-Kmeans-Transformer-GRU时序聚类状态识别组合模型&#xff0c;创新发文无忧&#xff01; 目录 GA-Kmeans-Transformer-GRU时序聚类状态识别组合模型&#xff0c;创新发文无忧&#xff01;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.GA-Kmeans-Transformer-GRU时…

0601大学物理电磁篇 静电场中的导体和电介质

静电场中的导体和电介质01 6-1静电场中的导体 6-1静电场中的导体