# [BZOJ2005][NOI2010]能量采集（莫比乌斯反演）

## 题解

i=1nj=1m(gcd(i,j)21)$\sum\limits_{i=1}^n\sum\limits_{j=1}^m (gcd(i,j)*2-1)$
=2i=1nj=1mgcd(i,j)nm$=2*\sum\limits_{i=1}^n\sum\limits_{j=1}^m gcd(i,j)-n*m$

i=1nj=1mgcd(i,j)$\sum\limits_{i=1}^n\sum\limits_{j=1}^m gcd(i,j)$
=i=1nj=1md|gcd(i,j)ϕ(d)$=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{d|gcd(i,j)} \phi(d)$
=i=1nj=1md=1n[d|i][d|j]ϕ(d)$=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{d=1}^n[d|i][d|j]\phi(d)$
=d=1ni=1n[d|i]j=1m[d|j]ϕ(d)$=\sum\limits_{d=1}^n\sum\limits_{i=1}^n[d|i]\sum\limits_{j=1}^m[d|j]\phi(d)$
=d=1nndmdϕ(d)$=\sum\limits_{d=1}^n\lfloor{n\over d}\rfloor\lfloor{m\over d}\rfloor\phi(d)$

## 代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long

const int max_n=1e5+5;

LL n,m,ans;
LL p[max_n],phi[max_n],prime[max_n];

inline void get_phi(){
phi[1]=1;
for (int i=2;i<=n;++i){
if (!p[i]){
prime[++prime[0]]=i;
phi[i]=i-1;
}
for (int j=1;j<=prime[0]&&i*prime[j]<=n;++j){
p[i*prime[j]]=1;
if (i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else
phi[i*prime[j]]=phi[i]*(prime[j]-1);

}
phi[i]+=phi[i-1];
}
}

int main(){
scanf("%lld%lld",&n,&m);
if (n>m) swap(n,m);
get_phi();
for (LL i=1,j;i<=n;i=j+1){
j=min(n/(n/i),m/(m/i));
ans+=(LL)(phi[j]-phi[i-1])*(n/i)*(m/i);
}
printf("%lld\n",ans*2-n*m);
}

## 总结

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客