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[k]=-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;
}