[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;
}
posted @ 2018-01-05 16:08  Mrha  阅读(...)  评论(...编辑  收藏