peiwenjun's blog 没有知识的荒原

P4240 毒瘤之神的考验 题解

题目描述

\(T\) 组询问,给定 \(n,m\) ,求 \(\left(\sum_{i=1}^n\sum_{j=1}^m\varphi(ij)\right)\bmod 998244353\)

数据范围

  • \(1\le T\le 10^4,1\le n,m\le 10^5\)

时间限制 \(\texttt{2s}\) ,空间限制 \(\texttt{512MB}\)

分析

首先有一个经典结论:

\[\varphi(ij)=\frac{\varphi(i)\varphi(j)\gcd(i,j)}{\varphi(\gcd(i,j))}\\ \]

证明:

\(v_p(i)=\alpha,v_p(j)=0\) ,则 \(p\) 在两边的贡献均为 \(p^{\alpha-1}(p-1)\)

\(v_p(i)=\alpha,v_p(j)=\beta\) ,则 \(p\) 在左边的贡献为 \(p^{\alpha+\beta-1}(p-1)\) ,右边的贡献为 \(p^{\alpha-1}(p-1)\cdot p^{\beta-1}(p-1)\cdot\frac p{p-1}=p^{\alpha+\beta-1}(p-1)\)

其实证明很 \(\texttt{naive}\) ,真正有用的是把这个式子积累下来,如果忘了也可以通过比较 \(\varphi(i)\varphi(j)\)\(\varphi(ij)\) 的差距现推。

接下来是常规操作。

\[\begin{aligned} &\sum_{i=1}^n\sum_{j=1}^m\frac{\varphi(i)\varphi(j)\gcd(i,j)}{\varphi(\gcd(i,j))}\\ &=\sum_{d=1}^\infty\frac d{\varphi(d)}\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=d]\varphi(i)\varphi(j)\\ &=\sum_{d=1}^\infty\frac d{\varphi(d)}\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}[\gcd(i,j)=1]\varphi(id)\varphi(jd)\\ &=\sum_{d=1}^\infty\frac d{\varphi(d)}\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}\sum_{x\mid\gcd(i,j)}\mu(x)\varphi(id)\varphi(jd)\\ &=\sum_{d=1}^\infty\frac d{\varphi(d)}\sum_{x=1}^\infty\mu(x)\sum_{i=1}^{n/dx}\varphi(idx)\sum_{j=1}^{n/dx}\varphi(jdx)\\ &=\sum_{t=1}^\infty\sum_{d\mid t}\frac d{\varphi(d)}\mu(\frac td)\sum_{i=1}^{n/t}\varphi(it)\sum_{j=1}^{m/t}\varphi(jt)\\ \end{aligned} \]

\(f(t)=\sum_{d\mid t}\frac d{\varphi(d)}\mu(\frac td),g(t,n)=\sum_{i=1}^n\varphi(it)\) ,则 \(f\) 可以 \(\mathcal O(n\log n)\) 预处理, \(g\) 的状态数为调和级数,同样可以 \(\mathcal O(n\log n)\) 预处理。

原式化为:

\[\sum_{t=1}^\infty f(t)\cdot g(t,\frac nt)\cdot g(t,\frac mt)\\ \]

虽然看到了 \(\frac nt,\frac mt\) ,但是不能整除分块。这是因为 \(g\) 内部仍然和 \(t\) 有关。

\(w=10^5\) ,考虑根号分治

  • 如果 \(t\le\frac nB\) ,暴力枚举 \(t\) 即可,时间复杂度 \(\mathcal O(\frac wB)\)
  • 如果 \(t\gt\frac nB\) ,则 \(\frac nt\le B\) 。对 \(\forall 1\le m\le n\le B\) ,预处理 \(s(n,m,k)=\sum_{t=1}^kf(t)\cdot g(t,n)\cdot g(t,m)\) ,整除分块可以做到 \(\mathcal O(B)\) 回答。

由于 \(g\) 要求 \(kn\le w\) ,因此 \(s\) 的状态数为 \(\sum_{n=1}^B\sum_{m=1}^n\frac wn=wB\) ,可以接受。

时间复杂度 \(\mathcal O(wB+T(B+\frac wB))\) ,取 \(B=\sqrt w\) ,时空复杂度均为 \(\mathcal O(w\sqrt w)\)

#include<bits/stdc++.h>
using namespace std;
const int B=200,maxn=1e5+5,mod=998244353;
int m,n,t,res;
int p[maxn],mu[maxn],phi[maxn];
int f[maxn];
vector<int> g[maxn],s[B+5][B+5];
bitset<maxn> b;
int qpow(int a,int k)
{
    int res=1;
    for(;k;a=1ll*a*a%mod,k>>=1) if(k&1) res=1ll*res*a%mod;
    return res;
}
void init(int n)
{
    mu[1]=phi[1]=1;
    for(int i=2,cnt=0;i<=n;i++)
    {
        if(!b[i]) p[++cnt]=i,mu[i]=-1,phi[i]=i-1;
        for(int j=1;j<=cnt&&i*p[j]<=n;j++)
        {
            b[i*p[j]]=1;
            if(i%p[j]==0)
            {
                phi[i*p[j]]=phi[i]*p[j];
                break;
            }
            mu[i*p[j]]=-mu[i],phi[i*p[j]]=phi[i]*(p[j]-1);
        }
    }
    for(int i=1;i<=n;i++)
    {
        g[i].resize(n/i+5);
        for(int j=1,inv=qpow(phi[i],mod-2);i*j<=n;j++)
        {
            f[i*j]=(f[i*j]+1ll*i*inv*mu[j])%mod;
            g[i][j]=(g[i][j-1]+phi[i*j])%mod;
        }
    }
    for(int i=1;i<=B;i++)
        for(int j=1;j<=i;j++)
        {
            s[i][j].resize(n/i+5);
            for(int k=1;k<=n/i;k++)
                s[i][j][k]=(s[i][j][k-1]+1ll*f[k]*g[k][i]%mod*g[k][j])%mod;
        }
}
int main()
{
    scanf("%d",&t),init(maxn-5);
    while(t--)
    {
        scanf("%d%d",&n,&m),res=0;
        if(n<m) swap(n,m);
        for(int i=1;i<=min(n/B,m);i++) res=(res+1ll*f[i]*g[i][n/i]%mod*g[i][m/i])%mod;
        for(int l=n/B+1,r=0;l<=m;l=r+1)
        {
            r=min(n/(n/l),m/(m/l));
            res=(0ll+res+s[n/l][m/l][r]-s[n/l][m/l][l-1])%mod;
        }
        printf("%lld\n",(res+mod)%mod);
    }
    return 0;
}

posted on 2024-11-26 18:32  peiwenjun  阅读(18)  评论(0)    收藏  举报

导航