快速幂+高精乘(填坑)洛谷1226+1045

引言

最近在刷题的时候偶然见到这样一个题目,见下图

 大致的意思是,让我们计算a的b次方取模p的结果,再我了解了关于快速幂的内容之后,很快便解决了这道题,每次乘完a后取模最后就可以得到结果。但是在这之后,我又碰到了这样一道题,见下图

这个魔性的题目竟然让我求后五百位?这种题用C语言所给的基础内置类型就行不通了 ,可能聪明的你会让人想到高精度,高精+和-我在之前博客中已经讲过,这道题是要求掌握高精度的乘法才能进一步将此题求解,我在求解完这道题后,便想将之前遗留的坑填上,便写了此篇博客。

快速幂

但是看完题先别急,想让我们看看什么是快速幂。

1.a的平方是a^2,a^2的平方是a^4,以此类推a^8,a^16,a^32。。。

2.a^x * a^y = a^(x+y) 这个也好理解

3.如果我们将b(幂的大小)写成二进制呢?

  假设b⑩ = 13  那么b② = 1101

  由此我们便可以将a^13,转化成a^8 * a^4 * a^0,而所乘的位数刚好与二进制的一相对应

  也就是说,我们可以先自增一个幂次方,每当b出现一位等于1时,向结果乘上一个事先自      增好的幂次方 当遍历完所有b二进制中1的位,便能得到最终的结果。

如果上面的话还没理解,可以结合下面的代码辅助理解,大体的意思就是,不需要一个一个往上乘a,根据幂的二进制直接乘a的更高幂次,减少计算。

while (b > 0) {//代码中用到了&(按位与)和>>(移位符)
	if (b & 1) {
//&的作用是比对两个数二进制的每一位,同为1为1,存在0则0
   //b = 1 1 0 1
   //1 = 0 0 0 1
//result 0 0 0 1
		ans = ans * a;//当b&1为真时乘上事先准备的幂次方a,存入结果中
	}
	a = a * a;
	b = b >> 1;
//将二进制位同时向右移动一位,高位补符号位
   //b = 1 1 0 1
//b>>1 = 0 1 1 0
//高位补符号位,详情可以去专门看一下我之前的博客或者别人的讲解
//b = b>>1 将结果赋给b
}

这样算下来,最终存在ans的结果便是a的b次方了

总的来说,如果 b 在二进制上的某一位是 1,我们就把答案乘上对应的 a^2^n。如果还是不太理解可以看看下面的代码实现,也是第一道题的答案

#include<stdio.h>
int main()
{
	long long int a, b, p, ans = 1;
	scanf("%lld%lld%lld", &a, &b, &p);
	long long int ar = a, br = b;
	while (b > 0) {
		if (b & 1) {
			ans = ans * a % p;//每次注意取模防止数字过大内置类型存不下
		}
		a = a * a % p;
		b = b >> 1;
	}
	ans = ans % p;
	printf("%lld^%lld mod %lld=%lld", ar, br, p, ans);
	return 0;
}

看完代码后,是不是就清晰多了?

但我们要考虑一件事,指数的增长速度那么快,用内置类型肯定,放不下,我们用高精度如何?

高精度乘

在了解这种乘法之前,我们可以回忆一下咱们小学的时候是怎样学习乘法运算的。

举个例子——12*19

 怎么理解呢?我们可以在这个式子中找找规律,比如右边个位的2和9都是在第0位(由于将数字放入数组中时是从第0位放起),它们相乘也是从第0位开始,19的1和12的2一个是第1位一个是第0位,它们相乘的结果便从第一位开始,而19的1和12的1两个都是第1位,它们在算式计算相加的时候便从第2位也就是百位开始。以上反应的规律总结以下就是

 for (int q = 0; q < la; q++) {
        for (int p = 0; p < lb; p++) {
            sum[q + p] += a[q] * b[p];
        }
}
 for(int q=0;q<la>lb?la + 3:lb + 3;q++){
    sum[q + p + 1] += sum[q + p] / 10;
    sum[q + p] %= 10;
}

在运用高精乘的过程中,也需要注意关于输入过大放不下的问题,这时候就需要用到字符串的处理,可以看看下方我专门写的一份用于高精乘的代码。

#include <stdio.h>
#include <string.h>
int main()
{
    char a0[5008];
    char b0[5008];
    int a[5008] = { 0 };
    int b[5008] = { 0 };
    int sum[5008] = { 0 };
    int i = 0;
    scanf("%s", a0);
    scanf("%s", b0);
    int v = 0;
    for (v = 5001; a0[v] != '\0'; v--);
    v--;
    for (int c = 0; v >= 0; c++, v--) {
        a[c] = a0[v] - '0';
    }
    for (v = 5002; b0[v] != '\0'; v--);
    v--;
    for (int c = 0; v >= 0; c++, v--) {
        b[c] = b0[v] - '0';
    }
    //以上代码将字符串转为数字放入数组
    int la = strlen(a0);
    int lb = strlen(b0);
    int lc = la + lb;
    for (int q = 0; q < la; q++) {
        for (int p = 0; p < lb; p++) {
            sum[q + p] += a[q] * b[p];
        }
    }
    for(int q=0;q<la>lb?la + 3:lb + 3;q++){
        sum[q + p + 1] += sum[q + p] / 10;
        sum[q + p] %= 10;
    }
    //以上代码进行高精乘
    int j = 0;
    for (j = 5005; sum[j] == 0; j--);
    for (; j >= 0; j--)
        printf("%d", sum[j]);
    //以上代码打印结果
    return 0;
}

当快速幂遇见高精乘 

这时候再将开始那道题搬运下来看看

这道题说白了最后要求求后500位其实是之前两者知识点的结合体,不过先讲讲第一问,问你位数,由于2^P-1的结果与2^P是相同的,所以可以列方程

 

 m刚刚好就是最终位数,在math.h中有计算lg的函数我们直接调用即可。

最终代码放到下面,配上注释

#include<stdio.h>
#include<math.h>
int arr[505];//充当计算2的幂次方的一个过程
int sign[505];//存放2的幂次方
int res[505];//充当最终结果的一个过程
int now[505];//存放最终结果
int main()
{
	int P;
	int ws; int i, j;
	scanf("%d", &P);
	ws = P * log10(2) + 1;
	sign[0] = 2;
	res[0] = 0;
	now[0] = 1;
	while (P > 0) {
		if (P & 1) {//当P&1为真,结果乘上2的幂次方
			for (i = 0; i <= 500; i++) {
				for (j = 0; j <= 500; j++) {
					if (i + j <= 500)//防止计算越界
						res[i + j] += now[i] * sign[j];
				}
			}
			for (i = 0; i <= 500; i++) {
				if (res[i] > 9) {
					res[i + 1] += res[i] / 10;
					res[i] %= 10;
				}
			}
			for (i = 0; i <= 500; i++) {
				now[i] = res[i];
				res[i] = 0;//用完res后要清零
			}
		}
        //下面是2的幂次方的自乘和自增
		for (i = 0; i <= 500; i++) {
			for (j = 0; j <= 500; j++) {
				if (i + j <= 500)//防止计算越界
					arr[i + j] += sign[i] * sign[j];
			}
		}
		for (i = 0; i <= 500; i++) {
			if (arr[i] > 9) {
				arr[i + 1] += arr[i] / 10;
				arr[i] %= 10;
			}
		}
		for (i = 0; i <= 500; i++) {
			sign[i] = arr[i];
			arr[i] = 0;//用完arr计算2的幂次方后清零
		}
		P >>= 1;//二进制P右移一位
	}
	now[0]--;//最终结果减一
	printf("%d\n", ws);
	for (i = 499,j=0; i >= 0; i--) {//华丽打印结果
		printf("%d", now[i]);
		j++;
		if (j >= 50) {
			printf("\n");
			j = 0;
		}
	}
	return 0;
}

结语

以上便是本次快速幂以及高精度乘法的所有内容,如果感觉对你有帮助的话,还请点个小小的赞,留下关注收藏再走啊!比心-----♥ 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

淡化了技术指标 还能做现货黄金交易?

技术指标是分析和预测现货黄金走势的其中一种方法&#xff0c;普通投资者多数依赖技术指标为自己的交易做判断。然而&#xff0c;近几年有一种观点认为&#xff0c;我们应该淡化技术指标&#xff0c;少使用或者不用技术分析来服务我们的交易。这个观点引起了不少投资者的思考&a…

NFTScan | 12.04~12.10 NFT 市场热点汇总

欢迎来到由 NFT 基础设施 NFTScan 出品的 NFT 生态热点事件每周汇总。 周期&#xff1a;2023.12.04~ 2023.12.10 NFT Hot News 01/ NFTScan 与 MintCore 联合推出适用于 NFT 的 Layer2 网络 Mint 12 月 5 日&#xff0c;根据官方消息&#xff0c;NFT 基础设施服务商 NFTScan …

Ajax跨域请求

最近使用js构造请求时发生了CORS跨域问题&#xff0c;mark一下 ajax跨域&#xff0c;这应该是最全的解决方案了 | Dailc的个人主页Everything about dailchttps://dailc.github.io/2017/03/22/ajaxCrossDomainSolution.htmlAJAX - 廖雪峰的官方网站研究互联网产品和技术&#…

基于SSM的乡镇篮球队管理系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本乡镇篮球队管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信…

华为云CodeArts Artifact:保障制品质量与安全的最佳选择

近期&#xff0c;为降低用户使用成本、满足个性化选择诉求&#xff0c;华为云制品仓库CodeArts Artifact 从软件开发生产线 CodeArtS 解耦出来&#xff0c;可单独购买。这是一款打破了传统制品管理的限制&#xff0c;高效、安全、好用的软件包管理工具。 体验通道&#xff1a;…

独热编码和词向量的简单理解

把单词用向量表示&#xff0c;是把深度神经网络语言模型引入自然语言处理领域的一个核心技术。想要让机器理解单词&#xff0c;就必须要把它变成一串数字&#xff08;向量&#xff09;。下面介绍的 One-Hot Encoding&#xff08;One-Hot 编码&#xff09;和 Word Embedding &am…

接口自动化框架Pytest —— 配置文件pytest.ini的详细使用

前言 我们在执行用例的时候&#xff0c;每次都在命令行中输入-v&#xff0c;-s等一些命令行参数的时&#xff0c;比较麻烦。其中pytest.ini这个配置文件可以快速的帮助我们解决这个问题。 配置文件 pytest.ini文件是pytest的主配置文件&#xff0c;可以改变pytest的运行方式…

Async 异步任务注解类的用法及原理分析

背景 看项目源码发现有一个 Async 注解&#xff0c;它是 Spring 的一个注解&#xff0c;作用是在独立的线程中完成注解方法的操作&#xff0c;底层原理是动态代理。 之前不知道这个知识点&#xff0c;小小测试了一下&#xff0c;发现项目中这个注解的用法是错误的&#xff0c…

Cypress安装与使用教程(2)—— 软测大玩家

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…

JVM学习笔记-如何在IDEA打印JVM的GC日志信息

若要在Idea上打印JVM相应GC日志&#xff0c;其实只需在Run/Debug Configurations上进行设置即可。 拿《深入Java虚拟机》书中的3-7代码例子来演示&#xff0c;如 1 public class JvmTest {2 private static final int _1MB1024*1024;3 public static void main(String…

AI 技术在前端开发流程中如何应用??3分钟带你一览开放原子开发者大会 OpenTiny 最新资讯!

大会简介 作为开放原子开源基金会的年度盛典&#xff0c;2023 开放原子开发者大会秉持遵循“共建、共治、共享”原则&#xff0c;以“一切为了开发者”为主题。本次大会汇聚顶尖开源人才&#xff0c;共享交流平台&#xff0c;通过吸引和邀请顶尖专家分享见解&#xff0c;设置技…

Leetcode—380.O(1) 时间插入、删除和获取随机元素【中等】

2023每日刷题&#xff08;五十七&#xff09; Leetcode—380.O(1) 时间插入、删除和获取随机元素 算法思想 实现代码 class RandomizedSet { public:vector<int> nums;unordered_map<int, int> dict;RandomizedSet() {srand((unsigned)time(NULL));}bool insert(…

关于核心转储和GDB调试的理解

Linux应用程序发生Segmentation fault段错误时&#xff0c;如何利用core dump文件定位错误呢&#xff1f; 在 Linux 系统中&#xff0c;常将“主内存”称为核心(core)&#xff0c;而核心映像(core image) 就是 “进程”(process)执行当时的内存内容。当进程发生错误或收到“信…

嵌入式系统复习--ARM技术概述

文章目录 上一篇ARM体系结构Thumb技术介绍ARM处理器工作状态ARM的异常响应过程ARM存储器接口及存储器层次下一篇 上一篇 嵌入式系统复习–概述 ARM体系结构 ARM体系结构的技术特征 ARM的体系结构采用了若干Berkeley RISC处理器的特征 Load/store体系结构固定的32为指令3地址…

每日一题 2454. 下一个更大元素 IV(困难,单调栈)

首先考虑第一大整数问题维护一个单调栈&#xff0c;遍历 nums&#xff0c;弹出栈中所有小于 nums[i] 的数&#xff0c;而 nums[i] 就是这些被弹出的数的第一大整数&#xff0c;知道栈为空或者栈顶元素比 nums[i] 大&#xff0c;证明如下&#xff0c;首先由于是遍历&#xff0c;…

C语言leetcode集训一:数组

为了进一步巩固C语言基础&#xff0c;同时进一步了解leetcode刷题的流程&#xff0c;开始进行C语言的集训&#xff0c;今天是第一天&#xff0c;看看我都做了哪些题&#xff0c;因为周末&#xff0c;有点颓废&#xff0c;所以基本上都是简单题&#xff0c;现在只想睡觉...... 有…

【无标题】树莓派 4B 多串口配置

0. 实验准备以及原理 0.1 实验准备 安装树莓派官方系统的树莓派 4B&#xff0c;有 python 环境&#xff0c;安装了 serial 库 杜邦线若干 屏幕或者可以使用 VNC 进入到树莓派的图形界面 0.2 原理 树莓派 4B 有 UART0&#xff08;PL011&#xff09;、UART1&#xff08;mini UAR…

YOLOv8改进实验:一文了解YOLOv8如何打印FPS指标

💡该教程为改进YOLOv8指南,属于《芒果书》📚系列,包含大量的原创首发改进方式🚀 💡🚀🚀🚀本博客内含改进源代码,按步骤操作运行改进后的代码即可 💡更方便的统计更多实验数据,方便写作 新增YOLOv8打印FPS指标 完善(一键YOLOv8打印FPS指标) 文章目录 完善…

MySQL - 事务隔离级别

MySQL 事务 本文所说的 MySQL 事务都是指在 InnoDB 引擎下&#xff0c;MyISAM 引擎是不支持事务的。 数据库事务指的是一组数据操作&#xff0c;事务内的操作要么就是全部成功&#xff0c;要么就是全部失败 事务具有原子性&#xff08;Atomicity&#xff09;、一致性&#xff0…

软件压力测试的重要性与用途

在当今数字化的时代&#xff0c;软件已经成为几乎所有行业不可或缺的一部分。随着软件应用规模的增加和用户数量的上升&#xff0c;软件的性能变得尤为关键。为了确保软件在面对高并发和大负载时仍然能够保持稳定性和可靠性&#xff0c;软件压力测试变得至关重要。下面是软件压…