luoguP1447 [NOI2010]能量采集
题意
显然答案是\(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}2*\gcd(i,j)-1\)
转化下即为:\((2*\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\gcd(i,j))-n*m\)
考虑如何求:\(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\gcd(i,j)\)
枚举\(gcd\),即求:
\(\sum\limits_{d=1}^{\min(n,m)}d*\sum\limits_{i=1}^n\sum\limits_{j=1}^m[gcd(i,j)=d]\)
这就是莫比乌斯反演裸题了,做法见这题。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
typedef long long ll;
int n,m;
ll ans;
int mu[maxn],sum[maxn];
bool vis[maxn];
vector<int>prime;
inline void shai(int n)
{
vis[1]=1;mu[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i])prime.push_back(i),mu[i]=-1;
for(unsigned int j=0;j<prime.size()&&i*prime[j]<=n;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)break;
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+mu[i];
}
inline ll solve(int n,int m,int d)
{
ll res=0;
for(int l=1,r;l<=min(n,m)/d;l=r+1)
{
r=min(n/(n/l),m/(m/l));
res+=1ll*(sum[r]-sum[l-1])*(n/(1ll*l*d))*(m/(1ll*l*d));
}
return res;
}
int main()
{
shai(100000);
scanf("%d%d",&n,&m);
for(int i=1;i<=min(n,m);i++)ans+=2ll*i*solve(n,m,i);
printf("%lld",ans-1ll*n*m);
return 0;
}