潜龙未见静水流,沉默深藏待时秋。一朝破空声势振,惊世骇俗展雄猷。
随笔 - 80, 文章 - 0, 评论 - 3, 阅读 - 2132

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

目录

题目描述

T 组数据,给定 nm ,求:

i=1nj=1mφ(lcm(i,j)gcd(i,j))

23333 取模。

数据范围

  • 1T3104,1mn5104

时间限制 2s ,空间限制 128MB

分析

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

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

ans=x=1ny=1m[gcd(x,y)=1]φ(xy)min(nx,my)

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


如果先枚举 d 再枚举 x,y

ans=d=1x=1n/dy=1m/d[gcd(x,y)=1]φ(xy)=d=1x=1n/dy=1m/d[gcd(x,y)=1]φ(x)φ(y)=d=1x=1n/dy=1m/du|gcd(x,y)μ(u)φ(x)φ(y)=d=1u=1μ(u)x=1n/duφ(ux)y=1m/duφ(uy)=d=1u=1μ(u)S(d,ndu)S(d,mdu)=t=1u|tμ(u)S(u,nt)S(u,mt)

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

S(d,n)=k=1nφ(dk)

要求 dn5104=w ,因此不同的 S 只有调和级数 wlogw 项,可以预处理。


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

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

  • 如果 twB ,二元组 (t,u) 只有 wBlogwB 项,暴力枚举即可。
  • 如果 t>wB ,则 nt,mt<B 。考虑对 1mn<B 预处理 F(n,m,k)=t=1ku|tμ(u)S(u,n)S(u,m) ,整除分块即可做到 O(B) 回答。

knwF 的状态数为:

n=1Bm=1nwn=wB

可以接受。

时间复杂度 O(wBlogw+T(wBlogwB+B)) ,空间复杂度 O(wB) 。理论上取 B=w ,可以得到最优的时间复杂度 O(wwlogw) 。但是为了平衡空间复杂度,代码中取 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   peiwenjun  阅读(7)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示