给出N,M
执行如下程序:
long long ans = 0,ansx = 0,ansy = 0;
for(int i = 1; i <= N; i ++)
for(int j = 1; j <= M; j ++)
if(gcd(i,j) == 1) ans ++,ansx += i,ansy += j;
cout << ans << " " << ansx << " " << ansy << endl;
求ans,比较简单
求ansx,(ansy同理)
定义A(i),gcd(a,b)=i时,加到ansx上的和
定义B(i),gcd(a,b)=i,2*i,3*i……时,加到ansx上的总和
B(i)=A(i)+A(2*i)+A(3*i)+……
莫比乌斯反演得:
A(i)=μ(1)*B(i)+μ(2)*B(2*i)+μ(3)*B(3*i)+……
A(1)=μ(1)*B(1)+μ(2)*B(2)+μ(3)*B(3)+……
B(i)=(n/i+1)*(n/i)/2*i * (m/i);
即可用莫比乌斯求解该题,再加上分块加速思想的优化。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#define ll long long
using namespace std;
#define N 100000
int mib[N+10];
int f[N+10];
ll ff[N+10];
bool vis[N+10];
void mobius()
{
int i,j;
for(i=1;i<=N;i++) mib[i]=1,vis[i]=false;
for(i=2;i<=N;i++)
{
if(vis[i]) continue;
for(j=i;j<=N;j+=i)
{
vis[j]=true;
if((j/i)%i==0)
{
mib[j]=0;
continue;
}
mib[j]=-mib[j];
}
}
f[0]=ff[0]=0;
for(i=1;i<=N;i++)
{
f[i]=f[i-1]+mib[i];
ff[i]=ff[i-1]+(ll)mib[i]*i;
}
}
int main()
{
int n,m,i,j,k;
mobius();
while(scanf("%d%d",&n,&m)!=EOF)
{
ll ans=0,ansx=0,ansy=0;
int t=min(n,m);
for(i=1;i<=t;i=j+1)
{
j=min(n/(n/i),m/(m/i));
ans+=(ll)(f[j]-f[i-1])*(m/i)*(n/i);
ansx+=(ll)(ff[j]-ff[i-1])*(n/i+1)*(n/i)/2*(m/i);
ansy+=(ll)(ff[j]-ff[i-1])*(m/i+1)*(m/i)/2*(n/i);
}
printf("%lld %lld %lld\n",ans,ansx,ansy);
}
}