[bzoj] 2005 能量采集 || 莫比乌斯反演
原题
给定n和m,求\(\sum^n_{i=1}\sum^m_{j=1}gcd(i,j)*2-1\)
我觉得这个题很难
是要用到莫比乌斯反演
大概参考了这个博客
本来想自己写的
但想想还是算咯
#include<cstdio>
#include<algorithm>
#define N 100000
typedef long long ll;
using namespace std;
bool b[N+10];
int n,m,f[N+10],s[N+10],num=0;
ll ans;
int read()
{
int ans=0,fu=1;
char j=getchar();
for (;j<'0' || j>'9';j=getchar()) if(j=='-') fu=-1;
for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
return ans*fu;
}
ll calc(int x)
{
int a=n/x,b=m/x;
ll sum=0;
for (int i=1,last;i<=a;i=last+1)
{
last=min(a/(a/i),b/(b/i));
sum+=1LL*(a/i)*(b/i)*(f[last]-f[i-1]);
}
return sum;
}
int main()
{
f[1]=1;
for (int i=2;i<=N;i++)
{
if (!b[i]) f[i]=-1,s[++num]=i;
for (int j=1;s[j]*i<=N;j++)
{
b[s[j]*i]=1;
if (i%s[j]==0) break;
f[s[j]*i]=-f[i];
}
f[i]+=f[i-1];
}
n=read();
m=read();
if (n>m) swap(n,m);
for (int p=1;p<=n;p++)
ans+=1LL*2*p*calc(p);
printf("%lld\n",ans-1LL*n*m);
return 0;
}