P3327 [SDOI2015]约数个数和 |莫比乌斯反演
题目描述
设 \(d(x)\) 为 \(x\) 的约数个数,给定 \(n,m\),求
\(\sum_{i=1}^n\sum_{j=1}^md(ij)\)
输入格式
输入文件包含多组测试数据。
第一行,一个整数 \(T\),表示测试数据的组数。
接下来的 \(T\) 行,每行两个整数 \(n,m\)。
输出格式
\(T\) 行,每行一个整数,表示你所求的答案。
\(d(ij)=\sum_{x|i}\sum_{y|i}[gcd(x,y)=1]\)
\(ANS=\sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|i}[gcd(x,y)=1]\)
\(ANS=\sum_{x=1}^n\sum_{y=1}^m \lfloor n/x\rfloor \lfloor m/y\rfloor[gcd(x,y)=1]\)
\(ANS=\sum_{x=1}^n\sum_{y=1}^m\sum_{d|gcd(x,y)}u(d) \lfloor n/x \rfloor \lfloor m/y\rfloor\)
\(令sum(n)=\sum_{x=1}^n\lfloor n/x \rfloor\)
\(ANS=\sum_{d=1}^nu(d)\sum_{x=1}^{n/d}\sum_{y=1}^{m/d}\lfloor n/x \rfloor \lfloor m/y\rfloor\)
\(ANS=\sum_{d=1}^nu(d)*sum(n/d)*sum(m/d)\)
\(O(n\sqrt n)\)预处理sum数组
\(O((n+T)\sqrt n)\)总复杂度
#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std;
const int N=5e5+10,M=5e4;
#define ll long long
#define int long long
inline int read(){
int x=0; char c=getchar();
while(c<'0'|c>'9')c=getchar();
while('0'<=c&&c<='9'){ x=(x<<1)+(x<<3)+(c^48); c=getchar(); }
return x;
}
inline ll sum(int m){//sqrt
ll ans=0;
for(int i=1,j=0;i<=m;i=j+1){
j=m/(m/i);
ans+=(j-i+1)*(m/i);
}
return ans;
}
ll mu[N],pri[N],f[N],tot;
bool vis[N];
inline void mubius(int n){
mu[1]=vis[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){ pri[++tot]=i; mu[i]=-1; }
for(int j=1;j<=tot&&pri[j]*i<=n;j++){
vis[i*pri[j]]=1;
if(i%pri[j])mu[i*pri[j]]=-mu[i];
else { mu[i*pri[j]]=0; break; }
}
}
for(int i=1;i<=n;i++)mu[i]+=mu[i-1],f[i]=sum(i);
}
signed main(){
int T=read(),n,m;
mubius(5e4);
while(T--){
n=read(),m=read();
ll ans=0;
int lim=min(n,m);
for(int i=1,j=0;i<=lim;i=j+1){//sqrt
j=min(n/(n/i),m/(m/i));
ans+=(mu[j]-mu[i-1])*f[n/i]*f[m/i];
}
printf("%lld\n",ans);
}
}
不以物喜,不以己悲