Challenge: Number of M-Coprime Arrays

Subdomeniu: Number Theory (number-theory)

Scor cont: 70.0 / 70

Submission status: Accepted

Submission score: 1.0

Submission ID: 464757847

Limbaj: cpp14

Link challenge: https://www.hackerrank.com/challenges/number-of-m-coprime-arrays/problem

Cerinta

An array of integers is called $m$-coprime if the following conditions are both satisfied:

- All the integers in the array are positive divisors of $m$.
- Each pair of adjacent elements in the array is [coprime](https://en.wikipedia.org/wiki/Coprime_integers) (i.e., element $i$ is always coprime with element $i + 1$).

Two arrays, $A$ and $B$, of size $n$ are *different* if and only if there exists an index $i$ such that $A[i] \ne B[i]$.

You are given $q$ queries where each query consists of integers $n$ and $m$. For each query, find the number of $m$-coprime arrays of size $n$, modulo $10^9 + 7$, and print it on a new line.

Input Format

The first line contains an integer, $q$, denoting the number of queries.    
Each of the $q$ subsequent lines contains two space-separated integers describing the respective values of $n$ (the size of the array) and $m$.

Output Format

For each query, print the number of $m$-coprime arrays of size $n$ modulo $10^9 + 7$ on a new line.

Constraints

- $1 \le q \le 100 $
- $1 \le n, m \le 10^{18}$

Cod sursa

#include <bits/stdc++.h>
using namespace std;

using u64 = unsigned long long;
using u128 = __uint128_t;

static const long long MOD = 1000000007LL;

static inline u64 mod_mul_u64(u64 a, u64 b, u64 mod) {
    return (u128)a * b % mod;
}

static inline u64 mod_pow_u64(u64 a, u64 e, u64 mod) {
    u64 r = 1 % mod;
    a %= mod;
    while (e > 0) {
        if (e & 1) r = mod_mul_u64(r, a, mod);
        a = mod_mul_u64(a, a, mod);
        e >>= 1;
    }
    return r;
}

bool isPrime64(u64 n) {
    if (n < 2) return false;
    for (u64 p : {2ULL, 3ULL, 5ULL, 7ULL, 11ULL, 13ULL, 17ULL, 19ULL, 23ULL, 29ULL, 31ULL, 37ULL}) {
        if (n % p == 0) return n == p;
    }

    u64 d = n - 1, s = 0;
    while ((d & 1) == 0) {
        d >>= 1;
        ++s;
    }

    // Deterministic MR bases for 64-bit.
    for (u64 a : {2ULL, 325ULL, 9375ULL, 28178ULL, 450775ULL, 9780504ULL, 1795265022ULL}) {
        if (a % n == 0) continue;
        u64 x = mod_pow_u64(a % n, d, n);
        if (x == 1 || x == n - 1) continue;
        bool comp = true;
        for (u64 r = 1; r < s; ++r) {
            x = mod_mul_u64(x, x, n);
            if (x == n - 1) {
                comp = false;
                break;
            }
        }
        if (comp) return false;
    }
    return true;
}

u64 pollardRho(u64 n) {
    if ((n & 1ULL) == 0ULL) return 2;
    static std::mt19937_64 rng((u64)chrono::high_resolution_clock::now().time_since_epoch().count());

    while (true) {
        u64 c = uniform_int_distribution<u64>(1, n - 1)(rng);
        u64 x = uniform_int_distribution<u64>(0, n - 1)(rng);
        u64 y = x;
        u64 d = 1;

        auto f = [&](u64 v) {
            return (mod_mul_u64(v, v, n) + c) % n;
        };

        while (d == 1) {
            x = f(x);
            y = f(f(y));
            u64 diff = x > y ? x - y : y - x;
            d = __gcd(diff, n);
        }
        if (d != n) return d;
    }
}

void factorRec(u64 n, map<u64, int> &mp) {
    if (n == 1) return;
    if (isPrime64(n)) {
        mp[n]++;
        return;
    }
    u64 d = pollardRho(n);
    factorRec(d, mp);
    factorRec(n / d, mp);
}

struct Mat2 {
    long long a00, a01, a10, a11;
};

Mat2 mulMat(const Mat2 &A, const Mat2 &B) {
    Mat2 C;
    C.a00 = ((u128)A.a00 * B.a00 + (u128)A.a01 * B.a10) % MOD;
    C.a01 = ((u128)A.a00 * B.a01 + (u128)A.a01 * B.a11) % MOD;
    C.a10 = ((u128)A.a10 * B.a00 + (u128)A.a11 * B.a10) % MOD;
    C.a11 = ((u128)A.a10 * B.a01 + (u128)A.a11 * B.a11) % MOD;
    return C;
}

Mat2 powMat(Mat2 base, unsigned long long exp) {
    Mat2 res{1, 0, 0, 1};
    while (exp > 0) {
        if (exp & 1ULL) res = mulMat(res, base);
        base = mulMat(base, base);
        exp >>= 1ULL;
    }
    return res;
}

long long waysForPrime(unsigned long long n, long long e) {
    // F(0)=1, F(1)=1+e, F(n)=F(n-1)+e*F(n-2)
    if (n == 0) return 1;
    if (n == 1) return (1 + e) % MOD;

    Mat2 M{1, e % MOD, 1, 0};
    Mat2 P = powMat(M, n - 1);

    long long F1 = (1 + e) % MOD;
    long long F0 = 1;
    long long Fn = ((u128)P.a00 * F1 + (u128)P.a01 * F0) % MOD;
    return Fn;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int q;
    cin >> q;
    while (q--) {
        unsigned long long n, m;
        cin >> n >> m;

        if (m == 1ULL) {
            cout << 1 << '\n';
            continue;
        }

        map<u64, int> fac;
        factorRec(m, fac);

        long long ans = 1;
        for (auto &kv : fac) {
            int e = kv.second;
            long long w = waysForPrime(n, e);
            ans = (u128)ans * w % MOD;
        }

        cout << ans << '\n';
    }

    return 0;
}
HackerRank Number Theory – Number of M-Coprime Arrays