大致题意: 让你求出(sum_{i=1}^nsum_{j=1}^nmu(gcd(i,j)))。
莫比乌斯反演
这种题目,一看就是莫比乌斯反演啊!(连莫比乌斯函数都有)
关于莫比乌斯反演,详见这篇博客:初学莫比乌斯反演。
推式子
下面让我们来推式子。
首先,我们采用解决这种问题的常用套路,来枚举(gcd),就能得到这样一个式子:
[sum_{d=1}^nsum_{i=1}^{lfloorfrac nd
floor}sum_{j=1}^{lfloorfrac nd
floor}[gcd(i,j)==1]mu(d)
]
将(mu(d))提前,可得:
[sum_{d=1}^nmu(d)sum_{i=1}^{lfloorfrac nd
floor}sum_{j=1}^{lfloorfrac nd
floor}[gcd(i,j)==1]
]
针对后半部分的式子,考虑当(i>j)时,其实等价于(i)和(j)交换后的答案。
这样一来,我们就可以想到把(j)的上限改为(i)。
注意(i=j)时,若(i=j=1),则(gcd(i,j)=1),其余情况(gcd(i,j))必定不为(1),因此要单独处理这种情况,将结果减(1)。
于是就得到这样一个式子:
[sum_{d=1}^nmu(d)(2sum_{i=1}^{lfloorfrac nd
floor}sum_{j=1}^i[gcd(i,j)==1]-1)
]
根据(phi)的定义可得,(sum_{j=1}^i[gcd(i,j)==1])其实就等于(phi(i)),因此可得:
[sum_{d=1}^nmu(d)(2sum_{i=1}^{lfloorfrac nd
floor}phi(i)-1)
]
这时的式子就已经足够简单了。
求答案
考虑如何求答案。
由于值域较大,因此我们必须使用杜教筛来筛(mu)和(phi)这两个函数。
由于后半部分的上限(lfloorfrac nd floor),因此我们必须使用除法分块来对这个式子进行优化。
这样就可以了。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define X 998244353
#define LL long long
#define Inc(x,y) ((x+=(y))>=X&&(x-=X))
#define Dec(x,y) ((x-=(y))<0&&(x+=X))
#define XSum(x,y) ((x)+(y)>=X?(x)+(y)-X:(x)+(y))
using namespace std;
LL n;
class DuSiever//杜教筛
{
private:
static const int SZ=10000000;int Pcnt,P[SZ+5],phi[SZ+5],mu[SZ+5],Sphi[SZ+5],Smu[SZ+5];
map<LL,int> Mphi,Mmu;
public:
I DuSiever()//初始化
{
RI i,j;for(phi[1]=mu[1]=1,i=2;i<=SZ;++i)
for(!P[i]&&(phi[P[++Pcnt]=i]=i-1,mu[i]=-1),j=1;j<=Pcnt&&1LL*i*P[j]<=SZ;++j)
if(P[i*P[j]]=1,i%P[j]) phi[i*P[j]]=phi[i]*(P[j]-1),mu[i*P[j]]=-mu[i];else {phi[i*P[j]]=phi[i]*P[j];break;}
for(i=1;i<=SZ;++i) Sphi[i]=XSum(Sphi[i-1],phi[i]),Smu[i]=XSum(XSum(Smu[i-1],mu[i]),X);
}
I int Gphi(Con LL& x)//筛phi
{
if(x<=SZ) return Sphi[x];if(Mphi.count(x)) return Mphi[x];
RI res=1LL*x%X*(x+1)%X*(X+1>>1)%X;Reg LL l,r;//千万注意此处x直接乘x+1会爆long long,因此要先取模(为此调了一个小时)
for(l=2;l<=x;l=r+1) r=x/(x/l),Dec(res,1LL*(r-l+1)*Gphi(x/l)%X);
return Mphi[x]=res;
}
I int Gmu(Con LL& x)//筛mu
{
if(x<=SZ) return Smu[x];if(Mmu.count(x)) return Mmu[x];
RI res=1;Reg LL l,r;
for(l=2;l<=x;l=r+1) r=x/(x/l),Dec(res,1LL*(r-l+1)*Gmu(x/l)%X);
return Mmu[x]=res;
}
}D;
int main()
{
RI ans=0;Reg LL l,r;for(scanf("%lld",&n),l=1;l<=n;l=r+1)//除法分块
r=n/(n/l),Inc(ans,1LL*(D.Gmu(r)-D.Gmu(l-1)+X)%X*((D.Gphi(n/l)<<1)-1)%X);
return printf("%d",ans),0;//输出答案
}