快速幂
快速幂是在 O(logk) 的复杂度下计算 akmodp 的结果。
可以用二进制的方式理解,令 k=∑bi2i,那么 ak=a∑bi2i=∏(a2i)bi,所以在每一次循环中处理出 a←a2 即可,相当于处理出 ai=ai−12=(a2i−1)2=a2i,类似于一个滚动数组优化。
1 2 3 4 5 6 7 8 9
| int qmi(int a, int k, int p) { int res = 1; while (k) { if (k & 1) res = 1ll * res * a % p; a = 1ll * a * a % p; k >>= 1; } return res; }
|
光速幂
当底数不变时,预处理出 a1∼aB−1 与 aB∼aB⌊n/B⌋,然后询问 ak 将其化为 akmodB+⌊k/B⌋B=akmodB×(aB)⌊k/B⌋ 即可,所以这样预处理的复杂度是 O(B+n/B),当 B=n 时最优为 O(n) 的复杂度。
为了方便书写,这里让 ai 与 aBi 最高都处理到 B−1,这样表达的最大幂次是 B(B−1)+B−1=B2−1,也就若幂次最高为 n 只要让 B2−1≥n 即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int el[B], blo[B];
void init(int x) { el[0] = blo[0] = 1;
for (int i = 1; i < B; i++) el[i] = el[i - 1] * x % P;
int b = el[B - 1] * x % P;
for (int i = 1; i < B; i++) blo[i] = blo[i - 1] * b % P; }
int get(int k) { return blo[k / B] * el[k % B] % P; }
|