普通快速幂在面对大量数据或单个够大数据时效率很低,这个时候我们就需要十进制快速幂,而如果模数是 long long 以内的数,我们可以用快速幂思想 $O(\text{log n})$ 完成快速乘,但我们其实可以 $O(1)$ 完成。
快速乘
这里直接说 $O(1)$ 的快速乘,利用 long double,而 long double 的精度其实只有 $19$ 位,直接乘是不行的,我们可以先除再乘,这样就不会出现精度问题,而前面直接计算 $a \times b$,再减去后面的部分,即使前面 $a \times b$ 爆负,它还会再爆一遍变为正的,保证了答案的正确。
1 2 3 4 5 6
typedeflongdouble ld; #define long long long
inlinelongmul(long a, long b){ return (a * b - (long)((ld)a / MOD * b) * MOD + MOD) % MOD; }
二进制快速幂
大家都会…
基础写法
1 2 3 4 5 6
inlinelongmodPow(long a, long b){ registerlong ret = 1; for (; b; b >>= 1, a = mul(a, a)) (b & 1) ? ret = mul(a, ret) : 0; return ret; }
库函数
其实还可以用 power 函数,power 函数先处理了二进制中的后缀 0,从而提高二进制快速幂的效率。
1 2 3 4 5
#include<ext/numeric>
intmain(){ std::cout << __gnu_cxx::power(3, 2); }
优化
就是上面的库函数里的优化…
1 2 3 4 5 6 7 8
inlinelongoptimizedModPow(long a, long b){ if (b == 0) return1; for (; ~b & 1; b >>= 1, a = mul(a, a)); registerlong ret = a; for (b >>= 1; b; b >>= 1) a = mul(a, a), (b & 1) ? ret = mul(a, ret) : 0; return ret; }
/* * created by xehoth on 14-04-2017 */ #include<bits/stdc++.h>
typedeflongdouble ld; #define long long long
constlong MOD = 999999999999999999ll; constint MAXN = 1000005;
inlinelongmul(long a, long b){ return (a * b - (long)((ld)a / MOD * b) * MOD + MOD) % MOD; }
inlinelongmodPow(long a, long b){ registerlong ret = 1; for (; b; b >>= 1, a = mul(a, a)) (b & 1) ? ret = mul(a, ret) : 0; return ret; }
inlinelongoptimizedModPow(long a, long b){ if (b == 0) return1; for (; ~b & 1; b >>= 1, a = mul(a, a)); registerlong ret = a; for (b >>= 1; b; b >>= 1) a = mul(a, a), (b & 1) ? ret = mul(a, ret) : 0; return ret; }
inlinelongquickPow(long a, char *b){ registerlong ret = 1; registerint n = strlen(b); for (registerint i = n - 1; i >= 0; i--) ret = mul(ret, optimizedModPow(a, b[i] - '0')), a = optimizedModPow(a, 10); return ret; }