惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
雷峰网
雷峰网
Hugging Face - Blog
Hugging Face - Blog
IT之家
IT之家
H
Help Net Security
腾讯CDC
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The GitHub Blog
The GitHub Blog
V
V2EX
M
MIT News - Artificial intelligence
Vercel News
Vercel News
WordPress大学
WordPress大学
博客园 - 三生石上(FineUI控件)
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
阮一峰的网络日志
阮一峰的网络日志
B
Blog RSS Feed
D
Docker
V
Visual Studio Blog
博客园 - 叶小钗
美团技术团队
S
SegmentFault 最新的问题
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com

博客园 - 糖豆爸爸

【树上DP前导知识汇总】 反向建图+拓扑排序 卡特兰数专题(Catalan) AcWing 126. 最大的和 AcWing 431. 守望者的逃离 AcWing 414. 数字游戏 AcWing 468. 魔法阵 AcWing 463. 求和 洛谷 P1632 点的移动 P1056 NOIP2008 普及组 排座椅 洛谷 P1889 士兵站队 洛谷 P1862 输油管道问题 CF444C DZY Loves Colors P2253 好一个一中腰鼓! SCOI2010 P2572 序列操作 P4344 SHOI2015 脑洞治疗仪 T125847 【模板】动态开点线段树 P3373 【模板】线段树 2 Physical Education Lessons
快速幂、龟速乘总结
糖豆爸爸 · 2023-11-13 · via 博客园 - 糖豆爸爸

快速幂、龟速乘总结

一、快速幂

\(a^b\ mod \ p\) 的结果。

\(Code\)

// 快速幂(不加mod)
int qmi(int a, int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = res * a;
        b >>= 1;
        a = a * a;
    }
    return res;
}

// 快速幂
int qmi(int a, int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = (res * a) % MOD;
        b >>= 1;
        a = a * a % MOD;
    }
    return res;
}

解释一下

假如我们需要计算\(2^{10}\),正常的办法是

   int s = 1;
   for (int i = 1; i <= 10; i++) s = s * 2;
   cout << s << endl;

毫无疑问,这个算法是正确的。但它执行的次数是\(10\)次,有没有什么办法可以优化一下运算次数呢?

优化

\(10\)进行二进制分解\((10)_{10}=(1010)_2\)
这样处理后,从后向前,借助于我们熟悉的数位分离模板,就是遍历二进制的每一位。

此时,我们发现,最左面的数字\(1\),权值是\(8\),第三位的数字权值是\(2\)

同时,\(2^8*2^2=2^{10}\)

为什么会有这么神奇的现象呢?其实就是因为幂运算的性质造成:

\[\large 2^{10}=2^{8+2}=2^8*2^2 \]

\(Q:\)为啥非得拆成\(8+2\),为啥不拆成\(7+3\)呢?
就是因为类似于 倍增 的办法在计算中好处理呗!

\(a\)在代码中的使命就是:我不管你用不用的上,反正我每次是翻倍!
而枚举\(b\)的每一个数位,就是看看这个位置上的当前\(a\)是不是需要乘进来!幂运算的性质成功的把幂与二进制加法结合起来了。

把倍增的思路\(2,4,8,16,32,...\)这样长上来的,这是因为
\(2^1*2^1=2^2\)
\(2^2*2^2=2^4\)
\(2^4*2^4=2^8\)
\(2^8*2^8=2^{16}\)
\(2^{16}*2^{16}=2^{32}\)

模板题 : \(P1226\) 【模板】快速幂||取余运算

二、龟速乘

\(a*b\ mod \ p\) 的结果,\(a,b,p\) 都是 \(10^{18}\) 级别。

\(Code\)

// 龟速乘,快速加
int qadd(int a, int b) {
    int res = 0;
    while (b) {
        if (b & 1) res = (res + a) % MOD;
        b >>= 1;
        a = (a + a) % MOD;
    }
    return res;
}

这东西怎么理解呢?

举栗子吧

\(5*6_{10}=5*(110)_2\)

最右侧的\(0\)对就的权值是\(5^1=5\)
右侧第二的\(1\)对就的权值是\(5*2=10\)
右侧第三的\(1\)对就的权值是\(10*2=20\)

\(② ③\)对应的位置上有数字\(1\),有效,\(①\)无效
结果就是\(10+20=30\)