Luogu 1447 - [NOI2010]能量採集 (莫比烏斯反演)
題意
給定\(n,m\),在座標系\((0,0)\) 位置有一個能量採集器
可行範圍為\(n\times m\)內的所有整數點(不包括座標軸上)
開採每個整數點會造成\(1\)能量損失
對於每個點\((x,y)\),如果\((0,0)\)與其連線上存在著\(cnt\)個其它整數點,那麼它的能量損失將會增加\(2\times cnt\)
即對於每個點,能量損失為\(2\times cnt_{(x,y)}+1\)
求\(n\times m\)範圍內所有點的能量損失之和,即求
\[\sum_{i=1}^n\sum_{j=1}^m2\times cnt_{(x,y)}+1 \]
限制
\(Case=1,\ 1\leq n,m\leq 10^5\)
思路
根據題意(或據圖可得)
每個點\((x,y)\)與\((0,0)\)點連線上的其餘整數點個數即為\(\gcd(x,y)-1\)
所以所求的答案即可轉化為
\[\begin{align} &\sum_{i=1}^n\sum_{j=1}^m2\times (\gcd(i,j)-1)+1\\ =&\sum_{i=1}^n\sum_{j=1}^m2\times \gcd(i,j)-1\\ =&2\times \sum_{i=1}^n\sum_{j=1}^m(\gcd(i,j))-n\times m\\ =&2\times \sum_{d=1}^{\min(n,m)}d\times\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=d] -n\times m\\ =&2\times \sum_{d=1}^{\min(n,m)}d\times\sum_{i=1}^{\frac n d}\sum_{j=1}^{\frac m d}[\gcd(i,j)=1] -n\times m\\ =&2\times \sum_{d=1}^{\min(n,m)}d\times\sum_{i=1}^{\frac{\min(n,m)}{d}}\mu(i)\lfloor\frac{\lfloor\frac n d\rfloor}{i}\rfloor\lfloor\frac{\lfloor\frac m d\rfloor}{i}\rfloor -n\times m\\ \end{align} \]
直接套板子即可
程式碼
Case Max (15ms/1000ms)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=100000; ll mu[N+50],prim[N+50]; bool vis[N+50]; void init(int n) { memset(vis,false,sizeof vis); mu[1]=1; int p=0; for(int i=2;i<=n;i++) { if(!vis[i]) { prim[p++]=i; mu[i]=-1; } for(int j=0;j<p;j++) { int k=i*prim[j]; if(k>n) break; vis[k]=true; if(i%prim[j]==0) { mu[k]=0; break; } else mu[i*prim[j]]=-mu[i]; } } } int main() { init(N); int n,m; scanf("%d%d",&n,&m); ll ansd,ans=0; int mn=min(n,m); for(int d=1;d<=mn;d++) { int mnd=mn/d,a=n/d,b=m/d; ansd=0; for(int i=1;i<=mnd;i++) ansd+=mu[i]*(a/i)*(b/i); ans+=ansd*d; } printf("%lld\n",ans*2-1LL*n*m); return 0; }