持续更新ing
唔。从年前就想要搞,但是一直鸽到现在。
不过,就从现在开始吧!!!
前导知识
目录
1.luogoP2568 GCD
2.luoguP2257 YY的GCD
1.luogoP2568 GCD
莫比乌斯反演的入门题。
思路:
设
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int N=1e7+100;
int n;
long long ans;
int vis[N],u[N],sum[N];
int p[N];
int cnt=0;
void seive(){
vis[0]=1;
vis[1]=1;
u[1]=1;
for(int i=2;i<=n;++i){
if(!vis[i])p[cnt++]=i,u[i]=-1;
for(int j=0;j<cnt&&(long long)p[j]*i<=n;++j){
vis[p[j]*i]=1;
u[p[j]*i]=-u[i];
if(i%p[j]==0){
u[p[j]*i]=0;
break;
}
}
}
for(int i=1;i<=n;++i)sum[i]=sum[i-1]+u[i];
}
long long g(int n){
long long ans=0;
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans+=(long long)(n/l)*(n/l)*(sum[r]-sum[l-1]);
}
return ans;
}
int main(){
scanf("%d",&n);
seive();
ans=0;
for(int i=0;i<cnt;++i)
ans+=g(n/p[i]);
printf("%lld\n",ans);
return 0;
}
2.luoguP2257 YY的GCD
思路:
设 ,。
根据莫比乌斯反演定理 得,
设
筛的时候先筛出来,再求,求得时候时间复杂度跟埃氏筛差不多。再对求前缀和。
然后就是整除分块的套路写法了。
代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e7+100;
int vis[N],u[N],p[N];
long long g[N],sum[N],ans;
int cnt,t,n,m;
void seive(){
vis[1]=1;
u[1]=1;
for(int i=2;i<N;++i){
if(!vis[i]){
p[cnt++]=i;
u[i]=-1;
}
for(int j=0;j<cnt&&(long long)p[j]*i<N;++j){
vis[p[j]*i]=1;
u[p[j]*i]=-u[i];
if(i%p[j]==0){
u[p[j]*i]=0;
break;
}
}
}
for(int i=0;i<cnt;++i)
for(int j=1;(long long)p[i]*j<N;++j)
g[p[i]*j]+=u[j];
for(int i=1;i<N;++i)sum[i]=sum[i-1]+g[i];
}
long long cal(int n,int m){
long long ans=0;
for(int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=(long long)(n/l)*(m/l)*(sum[r]-sum[l-1]);
}
return ans;
}
int main(){
seive();
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
if(n>m)n^=m^=n^=m;
ans=cal(n,m);
printf("%lld\n",ans);
}
return 0;
}