BZOJ4804 欧拉心算(莫比乌斯反演+欧拉函数+线性筛)

  一通套路后得Σφ(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;
}

猜你喜欢

转载自www.cnblogs.com/Gloid/p/9971132.html
今日推荐