# 【bzoj2005】能量采集【GCD】

((gcd1)2+1)=(gcd21)$\sum\left((gcd-1)*2+1\right)=\sum(gcd*2-1)$

ai=1bj=1gcd(i,j)$\quad\sum_{i=1}^a\sum_{j=1}^bgcd(i,j)$
d|nϕ(d)=n$\sum_{d|n}\phi(d)=n$
=ai=1bj=1d|gcd(i,j)ϕ(d)$=\sum_{i=1}^a\sum_{j=1}^b\sum_{d|gcd(i,j)}\phi(d)$
=ad=1a/di=1b/dj=11$=\sum_{d=1}^a\sum_{i=1}^{\lfloor a/d\rfloor}\sum_{j=1}^{\lfloor b/d\rfloor}1$
=ad=1adbd$=\sum_{d=1}^a\left\lfloor\frac ad\right\rfloor\left\lfloor\frac bd\right\rfloor$

#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=100001;
int prime[maxn/3],phi[maxn],tot;
bool isprime[maxn];
void genPrime(int n){
memset(isprime,true,sizeof isprime);
phi[1]=1;
for(int i=2;i<=n;++i){
if(isprime[i]){
prime[tot++]=i;
phi[i]=i-1;
}
for(int j=0;j<tot&&i*prime[j]<=n;++j){
isprime[i*prime[j]]=false;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
if(n>m) swap(n,m);
genPrime(m);
for(int i=1;i<=n;++i) phi[i]+=phi[i-1];
long long ans=0;

for(int i=1,nex;i<=n;i=nex+1){
nex=min(n/(n/i),m/(m/i));
ans+=1LL*(phi[nex]-phi[i-1])*(n/i)*(m/i);
}
cout<<ans*2-(long long)n*m<<"\n";
return 0;
}

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客