peiwenjun's blog 没有知识的荒原

P5572 [CmdOI2019] 简单的数论题 题解

题目描述

\(T\) 组数据,给定 \(n\ge m\) ,求:

\[\sum_{i=1}^n\sum_{j=1}^m\varphi(\frac{\text{lcm}(i,j)}{\gcd(i,j)})\\ \]

\(23333\) 取模。

数据范围

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

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

分析

首先是一个二维求和时拆 \(i,j\) 关系的小技巧,一般来说,先枚举 \(d=\gcd(i,j)\) 再枚举 \(x=\frac id,y=\frac jd\) 比先枚举 \(x,y\) 再枚举 \(d\) 有效得多

具体到本题,如果先枚举 \(x,y\) 再枚举 \(d\)

\[ans=\sum_{x=1}^n\sum_{y=1}^m[\gcd(x,y)=1]\varphi(xy)\min(\frac nx,\frac my)\\ \]

后面的 \(\min(\frac nx,\frac my)\) 没有很好的解决办法。


如果先枚举 \(d\) 再枚举 \(x,y\)

\[ans=\sum_{d=1}^\infty\sum_{x=1}^{n/d}\sum_{y=1}^{m/d}[\gcd(x,y)=1]\varphi(xy)\\ =\sum_{d=1}^\infty\sum_{x=1}^{n/d}\sum_{y=1}^{m/d}[\gcd(x,y)=1]\varphi(x)\varphi(y)\\ =\sum_{d=1}^\infty\sum_{x=1}^{n/d}\sum_{y=1}^{m/d}\sum_{u|\gcd(x,y)}\mu(u)\varphi(x)\varphi(y)\\ =\sum_{d=1}^\infty\sum_{u=1}^\infty\mu(u)\sum_{x=1}^{n/du}\varphi(ux)\sum_{y=1}^{m/du}\varphi(uy)\\ =\sum_{d=1}^\infty\sum_{u=1}^\infty\mu(u)S(d,\frac n{du})S(d,\frac m{du})\\ =\sum_{t=1}^\infty\sum_{u|t}\mu(u)S(u,\frac nt)S(u,\frac mt) \]

其中第一步利用了 \(\varphi\) 的积性,最后一步枚举 \(t=du\) 是另一个常见技巧,并且:

\[S(d,n)=\sum_{k=1}^n\varphi(dk) \]

要求 \(dn\le 5\cdot 10^4=w\) ,因此不同的 \(S\) 只有调和级数 \(w\log w\) 项,可以预处理。


到这里遇到了一点瓶颈。二元组 \((t,u)\)\(w\log w\) 项,内层虽然有 \(\frac nt,\frac mt\) ,但由于 \(u\) 是关于 \(t\) 的变量,不能整除分块。

接下来的操作和 P4240 一模一样,考虑根号分治

  • 如果 \(t\le\frac wB\) ,二元组 \((t,u)\) 只有 \(\frac wB\log\frac wB\) 项,暴力枚举即可。
  • 如果 \(t\gt\frac wB\) ,则 \(\frac nt,\frac mt\lt B\) 。考虑对 \(\forall 1\le m\le n\lt B\) 预处理 \(F(n,m,k)=\sum_{t=1}^k\sum_{u|t}\mu(u)S(u,n)S(u,m)\) ,整除分块即可做到 \(\mathcal O(B)\) 回答。

\(kn\le w\)\(F\) 的状态数为:

\[\sum_{n=1}^{B}\sum_{m=1}^n\frac wn=wB\\ \]

可以接受。

时间复杂度 \(\mathcal O(wB\log w+T(\frac wB\log\frac wB+B))\) ,空间复杂度 \(\mathcal O(wB)\) 。理论上取 \(B=\sqrt w\) ,可以得到最优的时间复杂度 \(\mathcal O(w\sqrt w\log w)\) 。但是为了平衡空间复杂度,代码中取 \(B=120\)

#include<bits/stdc++.h>
using namespace std;
const int B=120,maxn=5e4+5,mod=23333;
int m,n,t,cas,res;
int p[maxn],mu[maxn],phi[maxn];
bitset<maxn> b;
vector<int> d[maxn],s[maxn],f[B+5][B+5];
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++)
    {
        s[i].resize(n/i+5);
        for(int j=1;i*j<=n;j++) d[i*j].push_back(i),s[i][j]=s[i][j-1]+phi[i*j];
    }
    for(int i=1;i<=B;i++)
        for(int j=1;j<=i;j++)
        {
            f[i][j].resize(n/i+5);
            for(int k=1;k<=n/i;k++)
            {
                f[i][j][k]=f[i][j][k-1];
                for(auto u:d[k]) f[i][j][k]=(f[i][j][k]+1ll*mu[u]*s[u][i]*s[u][j])%mod;
            }
        }
}
int main()
{
    init(maxn-5);
    for(scanf("%d",&cas);cas--;)
    {
        scanf("%d%d",&n,&m),res=0;
        for(int t=1;t<=min(n/B,m);t++)
            for(auto u:d[t])
                res=(res+1ll*mu[u]*s[u][n/t]*s[u][m/t])%mod;
        for(int l=n/B+1,r=0;l<=m;l=r+1)
        {
            r=min(n/(n/l),m/(m/l));
            res=(res+f[n/l][m/l][r]-f[n/l][m/l][l-1])%mod;
        }
        printf("%d\n",(res+mod)%mod);
    }
    return 0;
}

posted on 2024-11-26 09:59  peiwenjun  阅读(34)  评论(0)    收藏  举报

导航