第一道莫比乌斯反演。。。$qwq$
设$f(d)=\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)==d]$
$F(n)=\sum_{n|d}f(d)=\lfloor \frac{N}{n} \rfloor \lfloor \frac{M}{n} \rfloor$
$f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d)$
$ans=\sum_{p\in pri}f(p)$
$=\sum_{p\in pri}\sum_{p|d}\mu(\frac{d}{p})F(d)$
设$d'=d/p$
$=\sum_{p\in pri}\sum_{d'}^{min(\lfloor \frac{N}{p} \rfloor,\lfloor \frac{M}{p} \rfloor)} \mu(d') F(d'p)$
$=\sum_{p\in pri}\sum_{d'}^{min(\lfloor \frac{N}{p} \rfloor,\lfloor \frac{M}{p} \rfloor)} \mu(d') \lfloor \frac{N}{d'p} \rfloor \lfloor \frac{M}{d'p} \rfloor$
设$T=d'p$
$=\sum_{T=1}^{min(N,M)}\sum_{t|T,t\in pri} \mu(\frac{T}{t}) \lfloor \frac{N}{T} \rfloor \lfloor \frac{M}{T} \rfloor$(其实上面这一段是为了更好理解拆$\sum$的过程)
$=\sum_{T=1}^{min(N,M)}\lfloor \frac{N}{T} \rfloor \lfloor \frac{M}{T} \rfloor \sum_{t|T,t\in pri} \mu(\frac{T}{t})$
对于$\lfloor \frac{N}{T} \rfloor \lfloor \frac{M}{T} \rfloor$用整除分块,对于$a(T)=\sum_{t|T,t\in pri} \mu(\frac{T}{t})$用一个类似埃筛的思路把$a(T)$筛出来然后做一个前缀和。。
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<cctype> #include<cstdlib> #include<vector> #include<queue> #include<map> #include<set> #define ll long long #define R register int using namespace std; namespace Fread { static char B[1<<15],*S=B,*D=B; #define getchar() (S==D&&(D=(S=B)+fread(B,1,1<<15,stdin),S==D)?EOF:*S++) inline int g() { R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix; do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix; } }using Fread::g; int t,n,m,cnt,pri[1000000],a[10000001],mu[10000001]; bool v[10000001]; long long sum[10000001]; inline void MU(int n) { mu[1]=1; for(R i=2;i<=n;++i) { if(!v[i]) pri[++cnt]=i,mu[i]=-1; for(R j=1;j<=cnt&&i*pri[j]<=n;++j) { v[i*pri[j]]=true; if(i%pri[j]==0) break; else mu[i*pri[j]]=-mu[i]; } } for(R j=1;j<=cnt;++j) for(R i=1;i*pri[j]<=n;++i) a[i*pri[j]]+=mu[i]; for(R i=1;i<=n;++i) sum[i]=sum[i-1]+(ll)a[i]; } signed main() { #ifdef JACK freopen("NOIPAK++.in","r",stdin); #endif MU(10000000); t=g(); while(t--) { register long long ans=0; n=g(),m=g(); n>m?(void)(swap(n,m)):(void)0; for(R l=1,r;l<=n;l=r+1) { r=min(n/(n/l),m/(m/l)); ans+=(ll)(n/l)*(m/l)*(sum[r]-sum[l-1]); }printf("%lld\n",ans); } }
2019.06.09