Search code examples
c++algorithmdiscrete-mathematicsmodular-arithmetic

Repeating Cycle of Modulus


Is there a efficient method to find the value of 1111..nmod M?
One can always use repeated squaring to find
100mod M + 101mod M + 102mod M + 103mod M + ...10nmod M
Is there any faster method than this?


Solution

  • You can solve this using an algorithm almost like exponentiation by squaring.

    First, if you have an even number of 1s, you can see that:

    11111111 = 1111     * 10001
    n ones     n/2 ones   (10^(n/2) + 1)
    

    which doubles the number of ones. Also,

    1111111 = 111111   * 10 + 1
    n ones    n-1 ones
    

    Formalising these observations, and for convenience naming the number with n ones 111...1 as J(n):

    • If n is even, J(n) = (10^(n/2) + 1)J(n/2).
    • If n is odd, J(n) = 10*J(n-1) + 1.

    You can use these recurrences (plus an actual implementation of exponentiation by squaring to compute 10^(n/2)) modulo M to compute the result in O(log(n)^2) time.

    Here's some C code that implements this. You'll have to use a longer type than int do avoid overflow if you want a large M (you need M^2 to fit into your type).

    #include <stdio.h>
    
    // Computes a to the power of n modulo m.
    int pow_mod_m(int a, int n, int m) {
        if (n == 0) { return 1; }
        if (n == 1) { return a; }
        if (n % 2 == 0) {
            int k = pow_mod_m(a, n/2, m);
            return (k * k) % m;
        }
        return (pow_mod_m(a, n-1, m) * a) % m;
    }
    
    // Computes J(n) modulo m
    int j_mod_m(int n, int m) {
        if (n == 1) {
            return 1;
        }
        if (n % 2 == 0) {
            return (j_mod_m(n/2, m) * (1 + pow_mod_m(10, n/2, m))) % m;
        }
        return (j_mod_m(n-1, m) * 10 + 1) % m;
    }
    
    int main(int argc, char**argv) {
        for (int i = 1; i < 1000; i++) {
            printf("%d: %d\n", i, j_mod_m(i, 12345));
        }
        return 0;
    }