当前位置 博文首页 > weixin_30800807的博客:BZOJ4804 欧拉心算(莫比乌斯反演+欧拉

    weixin_30800807的博客:BZOJ4804 欧拉心算(莫比乌斯反演+欧拉

    作者:[db:作者] 时间:2021-09-21 15:12

      一通套路后得Σφ(d)μ(D/d)?n/D?2。显然整除分块,问题在于怎么快速计算φ和μ的狄利克雷卷积。积性函数的卷积还是积性函数,那么线性筛即可。因为μ(pc)=0 (c>=2),所以f(pc)还是比较好算的,讨论一波即可。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 10000001
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int T,n,phi[N],mobius[N],prime[N],cnt;
    ll f[N];
    bool flag[N];
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4804.in","r",stdin);
        freopen("bzoj4804.out","w",stdout);
        const char LL[]="%I64d\n";
    #else
        const char LL[]="%lld\n";
    #endif
        T=read();
        flag[1]=1;mobius[1]=1;phi[1]=1;f[1]=1;
        for (int i=1;i<N;i++)
        {
            if (!flag[i]) prime[++cnt]=i,phi[i]=i-1,mobius[i]=-1,f[i]=i-2;
            for (int j=1;j<=cnt&&prime[j]*i<N;j++)
            {
                flag[prime[j]*i]=1;
                if (i%prime[j]==0)
                {
                    phi[prime[j]*i]=phi[i]*prime[j];
                    if ((i/prime[j])%prime[j]) f[prime[j]*i]=f[i/prime[j]]*(1ll*prime[j]*prime[j]-2*prime[j]+1);
                    else f[prime[j]*i]=f[i]*prime[j];
                    break;
                }
                mobius[prime[j]*i]=-mobius[i];
                phi[prime[j]*i]=phi[i]*(prime[j]-1);
                f[prime[j]*i]=f[i]*(prime[j]-2);
            }
        }
        for (int i=1;i<N;i++) f[i]+=f[i-1];
        while (T--)
        {
            n=read();ll ans=0;
            for (int i=1;i<=n;i++)
            {
                int t=n/(n/i);
                ans+=(f[t]-f[i-1])*(n/i)*(n/i);
                i=t;
            }
            printf(LL,ans);
        }
        return 0;
    }
    cs