Modular exponentiation with rEaLlY big exponents

Revision en1, by p_fire, 2023-05-01 10:09:08

17D - Notepad my submission history is embarrassing

Doing a number theory tour right now haha, this problem just wants you to compute $$$(b-1)\cdot b^{n-1} \bmod c$$$.

Intuitively, I tried to use a simple repeated squaring technique, but always got TL around test case 27 (in which b and c are around 10k digits). I thought python's builtin integer implementation was to blame, and some fiddling shows that python's Decimal module has a pretty slow division (they don't optimize for integers), so I switched to Java's BigInteger, which still is slow. Then it came to me the repeated squaring approach is O(L^2) where L is length of the exponent, not L*log(L) as I initially thought. No wonder it failed then because b and n can be 10^6 digits. On the good side, c is not so large, so Euler's totient theorem can help: just replace n-1 with $$$n-1 \bmod \phi(c)$$$. (You can compute the remainder of a large string modulo a fairly small number by going over its digits RTL, keeping track of the remainder of $$$10^i$$$.)

But this only works when b and c are coprime. For the non-coprime scenario, initial suggestions I found seemed complicated (computing gcd etc). Then I came across a note saying that in that case, it is still ok if you're willing to give in another $$$\phi(n)$$$. More precisely,

$$$a^b\equiv a^{(b\bmod \phi(n))+\phi(n)}\pmod n\text{ if }b\ge\phi(n).$$$

Stronger statements hold but I found the current form the easiest to implement since now nbcs about coprimality/gcd. So here's the recipe:

  1. Input b,n,c. Store b,n as strings and c as a number
  2. Compute r=(b-1)%c and s=b%c by looping on the digits (do s first to avoid string subtraction)
  3. Factorize c and compute $$$\phi(c)$$$
  4. We want t to satisfy $$$s^t\equiv s^{n-1}$$$. From the discussion we can set t=(n-1)%phi(c), and if this is not n-1 then add $$$\phi(c)$$$ to t.
  5. Use fast exponentiation to find (r*s^t) % c. This time it's really fast, because r,s,t,c are all within 2^31.

This approach would finish all the test cases within 300ms using PyPy, meanwhile still TLing with python, LOL.

Tags number theory

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en1 English p_fire 2023-05-01 10:09:08 2119 Initial revision (published)