P1447 [NOI2010]能量采集
显然答案就是 $\sum_{i=1}^{n}\sum_{j=1}^{m}(2gcd(i,j)-1)$
把合式里面的系数 $2$ 和常数 $+1$ 提出来,变成 $2\sum_{i=1}^{n}\sum_{j=1}^{m}(gcd(i,j))-nm$
看到了有趣的 $gcd$ ,考虑莫比乌斯反演
设 $f[x]=\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==x]$
和 $F[x]=\sum_{i=1}^{n}\sum_{j=1}^{m}[x|gcd(i,j)]$
那么显然有 $F[x]=\sum_{x|d}f[d]$
然后考虑 $F[x]$ 的意义,其实就是对于 $i \in [1,n]\ ,\ j \in [1,m]$ 的所有整数对 $i,j$,他们同时有一个因数为 $x$ ,的数对 $i,j$ 的数量
显然有且只有 $x$ 的倍数有因数 $x$,所以对于 $[1,n]$ 的整数,有 $\left \lfloor \frac{n}{x} \right \rfloor$ 个数有因数 $x$
同理对于 $[1,m]$ 的整数,有 $\left \lfloor \frac{m}{x} \right \rfloor$ 个数有因数
这两组数可以任意两两组合都合法,所以
$F[x]=\left \lfloor \frac{n}{x} \right \rfloor\left \lfloor \frac{m}{x} \right \rfloor$
然后根据莫比乌斯反演的套路:如果 $F[x]=\sum_{x|d}f[d]$,那么 $f[x]=\sum_{d|x}u(\frac{d}{x})F[d]$
所以 $f[x]=\sum_{d|x}u(\frac{d}{x})F[d]$,直接预处理 $F$ 就行了
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=2e6+7; int n,m,mx,pri[N],mu[N],tot; ll f[N],F[N],Ans; bool not_pri[N]; void pre() { not_pri[1]=1; mu[1]=1; for(int i=2;i<=mx;i++) { if(!not_pri[i]) pri[++tot]=i,mu[i]=-1; for(int j=1;j<=tot;j++) { ll t=1ll*i*pri[j]; if(t>mx) break; not_pri[t]=1; if(!(i%pri[j])) break; mu[t]=-mu[i]; } } } int main() { n=read(),m=read(); mx=max(n,m); pre(); for(int i=1;i<=mx;i++) F[i]=1ll*(n/i)*(m/i); for(int i=1;i<=mx;i++) { for(int j=i;j<=mx;j+=i) f[i]+=mu[j/i]*F[j]; Ans+=f[i]*i; } Ans<<=1; Ans-=1ll*n*m; printf("%lld\n",Ans); return 0; }