洛谷 P5221 Product

\({\rm CYJian}\)最近闲的玩起了\(gcd\)。。他想到了一个非常简单而有意思的式子:

\[\prod_{i=1}^N\prod_{j=1}^N\frac{lcm(i,j)}{gcd(i,j)}\ (\bmod\ 104857601) \]

\({\rm CYJian}\)已经算出来这个式子的值了。现在请你帮他验算一下吧。\({\rm CYJian}\)只给你\(0.2s\)的时间哦。

\(1 \leq N \leq 1000000\)


把式子写成:

\[=\prod_{i=1}^N\prod_{j=1}^N\frac{ij}{gcd^2(i,j)}=\frac{\prod_{i=1}^N\prod_{j=1}^Nij}{(\prod_{i=1}^N\prod_{j=1}^Ngcd(i,j))^2} \]

上面的部分就是 \((N!)^{2N}\) ,对于下面 \(\prod_{i=1}^N\prod_{j=1}^Ngcd(i,j)\) 部分,考虑枚举 \(gcd\) 是多少,设 \(g(x,n)\) 表示 \(\sum_{i=1}^n\sum_{j=1}^n[gcd(i,j)==x]\) ,那么这个式子就变成了:

\[\prod_{i=1}^Ni^{g(i,N)} \]

考虑怎么求所有的 \(g(i,N)\) ,我们写出式子:

\[\begin{aligned}g(x,n)&=\sum_{i=1}^n\sum_{j=1}^n[gcd(i,j)==x]\\&=\sum_{i=1}^{\frac{n}{x}}\sum_{j=1}^{\frac{n}{x}}[gcd(i,j)==1]\\&=g(1,\frac{n}{x})\end{aligned} \]

然后考虑求 \(g(1,n)\) ,就有:

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

这个可以整除分块 \(\sqrt{n}\) 完成。

然后现在我们要求:

\[\prod_{i=1}^Ni^{g(1,\frac{N}{i})} \]

\(\frac{N}{i}\) 也整除分块,这样就可以做到 \(O(N+\sqrt N\log N)\) 的复杂度处理出来了。

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
const int N = 1e6;
const int M = 1e5;
const int p = 104857601;
using namespace std;
int n,mul[N + 5],prime[M + 5],pcnt,ans,s;
bool vis[N + 5];
int mypow(int a,long long x){int s = 1;for (;x;x & 1 ? s = 1ll * a * s % p : 0,a = 1ll * a * a % p,x >>= 1);return s;}
long long calc(int n)
{
    long long ans = 0;
    for (int l = 1,r;l <= n;l = r + 1)
    {
        r = n / (n / l);
        ans += 1ll * (n / l) * (n / l) * (mul[r] - mul[l - 1]);
    }
    return ans;
}
void prework()
{
    vis[1] = 1;mul[1] = 1;
    for (int i = 2;i <= n;i++)
    {
        if (!vis[i])
        {
            mul[i] = -1;
            prime[++pcnt] = i;
        }
        for (int j = 1;j <= pcnt && prime[j] * i <= n;j++)
        {
            vis[prime[j] * i] = 1;
            mul[prime[j] * i] = -mul[i];
            if (i % prime[j] == 0)
            {
                mul[prime[j] * i] = 0;
                break;
            }
        }
    }
    for (int i = 1;i <= n;i++)
        mul[i] += mul[i - 1];
}
int main()
{
    scanf("%d",&n);
    prework();
    ans = 1;
    for (int i = 1;i <= n;i++)
        ans = 1ll * ans * i % p;
    ans = mypow(ans,n);
    ans = 1ll * ans * ans % p;
    s = 1;
    for (int l = 1,r;l <= n;l = r + 1)
    {
        r = n / (n / l);
        int tmp = 1;
        for (int i = l;i <= r;i++)
            tmp = 1ll * tmp * i % p;
        s = 1ll * s * mypow(tmp,calc(n / l)) % p;
    }
    s = 1ll * s * s % p;
    ans = 1ll * ans * mypow(s,p - 2) % p;
    cout<<(ans + p) % p<<endl;
    return 0;
}
posted @ 2021-01-21 11:15  eee_hoho  阅读(83)  评论(0编辑  收藏  举报