快速乘总结
因为我们知道乘法有的时候会溢出,即使是
1. 复杂度为 O(log) 的快速乘:
我们知道乘法其实就是把很多个加法运算合到一起。现在我们的乘法会爆范围,那我们就把它转化为加法。但是我们不可能一个一个的加,这样复杂度会是
inline ll ksc(ll x, ll y, ll p) { //计算x乘y的积
ll res = 0; //加法初始化
while (y) {
if (y & 1) res = (res + x) % p; //模仿二进制
x = (x << 1) % p;
y >>= 1; //将x不断乘2达到二进制
}
return res;
}
// ll 表示 long long
/*=============================*/
//写法优化
inline ll ksc_best(ll x, ll y, ll mod) {
ll res = 0;
for (; y; y >>= 1, x = (x << 1) % mod)
if (y & 1) res = (res + x) % mod;
return res;
}
当然我们不一定要仿照2进制,也可以是其他进制,只要中间算每一位上数字代表值时不会爆
2. 优秀的 STL 结构:__int128
__int128是c++自带的一个数据类型,顾名思义,它可以装下
ll ans = ((__int128)x * y) % mod;
不过有一点遗憾的就是:比赛中基本上不会允许使用这个数据类型的
3. 非常优秀的 O(1) 快速乘
这个东西最初我感觉很不靠谱,但它就是能算出来正确答案。它就是用
inline ll ksc(ll x, ll y, ll p) {
ll z = (ld)x / p * y;
ll res = (ull)x * y - (ull)z * p;
return (res + p) % p;
}
// ll 表示 long long
// ld 表示 long double
// ull 表示 unsigned long long
// 一种自动溢出的数据类型(存满了就会自动变为0)
看到这份代码有没有感到十分奇怪? 它中间是直接用了乘法操作的啊!这不直接爆掉了吗?
但是它就是可以算出正确答案来。因为它其实很巧妙的运用了自动溢出这个操作,我们的代码中的z就表示
4. 关于快速乘的灵活转化:
我们知道快速乘的原理其实就是乘法转加法(上面这种不算),但是这是可以根据题目性质灵活转变的,我们如何转成加法决定了我们的复杂度,就像如果模数并没有超过
inline ll ksc(ll x, ll y, ll P) {
ll L = x * (y >> 25) % P * (1 << 25) % P;
ll R = x * (y & ((1 << 25) - 1)) % P;
return (L + R) % P;
}
在保证运算不会爆
5. 一些经常需要快速乘的算法:
Miller rabin 判大质数
Pollard Rho 大数因子寻找
BSGS 大步小步算法
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· 分享4款.NET开源、免费、实用的商城系统
· 解决跨域问题的这6种方案,真香!
· 一套基于 Material Design 规范实现的 Blazor 和 Razor 通用组件库
· 5. Nginx 负载均衡配置案例(附有详细截图说明++)