题解P5221 Product

P5221 Product

这题好像可以用莫反做,但数论分块似乎会被卡

\[\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_{i=1}^n\prod_{j=1}^nij\times\prod_{i=1}^n\prod_{j=1}^ngcd(i,j)^{-2} \]

首先看 \(\prod\limits_{i=1}^n\prod\limits_{j=1}^nij\)

\[=\prod_{i=1}^ni^n\prod_{j=1}^nj=\prod_{i=1}^ni^nn!=(n!)^n\times(n!)^n=(n!)^{2n} \]

接着尝试化简一下后面那一坨

\[\prod_{i=1}^n\prod_{j=1}^ngcd(i,j)=\prod_{d=1}^nd^{\sum\limits_{i=1}^n\sum\limits_{j=1}^n[gcd(i,j)=d]}\\=\prod_{d=1}^nd^{\sum\limits_{i=1}^{\frac{n}{d}}\sum\limits_{j=1}^{\frac{n}{d}}[gcd(i,j)=1]} \]

仔细观察一下指数,发现可以用莫反加数论分块,但时间复杂度就是 \(O(n\sqrt{n})\), 有点勉强,所以可以考虑欧拉函数 \(\sum\limits_{i=1}^n\sum\limits_{j=1}^i[gcd(i,j)=1]=\sum\limits_{i=1}^n\phi(i)\)

\(sum(n)=\sum\limits_{i=1}^n\phi(i)\) 那么上述式子的指数 \(=2\times sum(\lfloor\frac{n}{d}\rfloor)-1\)

\[\Rightarrow ans=(n!)^{2n}\times\prod_{d=1}^nd^{2\times sum(\lfloor\frac{n}{d}\rfloor)-1} \]

因为此题卡空间,数组不能开long long,所以需要用到欧拉定理 \(a^c\equiv a^{c~mod~\phi(m)}(mod~m)\), 这样就不需要开long long了

代码

#include<iostream>
#include<cstdio>
#define MOD (104857601)
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;

bool st[N];
int phi[N], prime[N], tot;

void init()
{
    phi[1] = 1;
    for (int i = 2; i < N; i++)
    {
        if (!st[i])
            prime[++tot] = i, phi[i] = i - 1;
        for (int j = 1; i * prime[j] < N; j++)
        {
            st[i * prime[j]] = true;
            if (i % prime[j] == 0)
            {
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
            phi[i * prime[j]] = phi[i] * (prime[j] - 1);
        }
    }
    for (int i = 1; i < N; i++)
        phi[i] = (phi[i] + phi[i - 1]) % (MOD - 1);
}

int qmi(int a, ll b)
{
    int res = 1;
    while (b)
    {
        if (b & 1)
            res = (ll)res * a % MOD;
        a = (ll)a * a % MOD;
        b >>= 1;
    }
    return res;
}

int main()
{
    init();
    int n;
    scanf("%d", &n);
    int ans = 1;
    for (int i = 1; i <= n; i++)
        ans = (ll)ans * i % MOD;
    ans = qmi(ans, 2 * n);
    int temp = 1;
    for (int i = 2; i <= n; i++)
        temp = (ll)temp * qmi(i, 2 * phi[n / i] - 1) % MOD;
    temp = (ll)temp * temp % MOD;
    temp = qmi(temp, MOD - 2);
    printf("%d", (ll)temp * ans % MOD);
    return 0;
}
posted @ 2021-04-22 16:34  DSHUAIB  阅读(44)  评论(0编辑  收藏  举报