P5221:Product 题解

推导过程

首先来一波正常套路,把枚举项变成\(\gcd\)。

\[ \begin{aligned} \prod_{i = 1}^n \prod_{j = 1}^n \frac{lcm(i, j)}{gcd(i, j)} &= \prod_{i = 1}^n \prod_{j = 1}^n \frac{ij}{gcd(i, j)^2} \\ &= \prod_{d = 1}^n d^{\sum_{i = 1}^n \sum_{j = 1}^n [\gcd(i, j) = d]} \end{aligned} \]

发现这个右上角的式子其实就是仪仗队:

\[ \begin{aligned} \sum_{i = 1}^n \sum_{j = 1}^n [\gcd(i, j) = d] &= \sum_{i = 1}^{\lfloor \frac{n}{d} \rfloor} \sum_{j = 1}^{\lfloor \frac{n}{d} \rfloor} [\gcd(i, j) = 1] \\ &= (2\sum_{i = 1}^{\lfloor \frac{n}{d} \rfloor} \varphi(i)) – 1 \end{aligned} \]

搞完了,稍稍卡下空间,然后用费马小定理来取模即可。

代码

// P5221.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e6 + 5, mod = 104857601;

int primes[MAX_N >> 1], tot, phi[MAX_N], n;
bitset<MAX_N> vis;

int quick_pow(int bas, int tim)
{
    int ret = 1;
    while (tim)
    {
        if (tim & 1)
            ret = 1LL * ret * bas % mod;
        bas = 1LL * bas * bas % mod;
        tim >>= 1;
    }
    return ret;
}

int main()
{
    scanf("%d", &n), phi[1] = 1;
    for (int i = 2; i <= n; i++)
    {
        if (!vis[i])
            primes[++tot] = i, phi[i] = (i - 1);
        for (int j = 1; j <= tot && 1LL * i * primes[j] <= n; j++)
        {
            vis[i * primes[j]] = true;
            if (i % primes[j] == 0)
            {
                phi[i * primes[j]] = phi[i] * primes[j];
                break;
            }
            phi[i * primes[j]] = phi[i] * phi[primes[j]];
        }
    }
    for (int i = 1; i <= n; i++)
        phi[i] = (2LL * phi[i] + phi[i - 1]) % (mod - 1);
    int ans = 1, tmp = 1;
    for (int i = 1; i <= n; i++)
        ans = 1LL * ans * i % mod;
    ans = quick_pow(ans, n << 1);
    for (int d = 2; d <= n; d++)
        tmp = 1LL * tmp * quick_pow(d, phi[n / d] - 1) % mod;
    printf("%lld\n", 1LL * ans * quick_pow(1LL * tmp * tmp % mod, mod - 2) % mod);
    return 0;
}

 


发表评论

邮箱地址不会被公开。 必填项已用*标注