BZOJ 4804 欧拉心算

Posted on 2017-03-31 23:04  ziliuziliu  阅读(287)  评论(0编辑  收藏  举报

要线性筛的时候可以这样子想:两个积性函数卷起来肯定是积性函数。

那么我们只需要知道g[p^r]就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 10000050
using namespace std;
int t,n,prime[maxn/10],tot=0,r[maxn],phi[maxn];
long long g[maxn];
bool vis[maxn];
void get_table()
{
    g[1]=r[1]=phi[1]=1;
    for (int i=2;i<=maxn-50;i++)
    {
        if (!vis[i])
        {
            prime[++tot]=i;
            g[i]=i-2;r[i]=i;phi[i]=i-1;
        }
        for (int j=1;j<=tot && i*prime[j]<=maxn-50;j++)
        {
            vis[i*prime[j]]=true;
            if (!(i%prime[j]))
            {
                r[i*prime[j]]=r[i]*prime[j];phi[i*prime[j]]=phi[i]*prime[j];
                g[i*prime[j]]=g[i*prime[j]/r[i*prime[j]]]*(long long)(phi[r[i*prime[j]]]-phi[r[i*prime[j]]/prime[j]]);
                break;
            }
            r[i*prime[j]]=prime[j];phi[i*prime[j]]=phi[i]*(prime[j]-1);
            g[i*prime[j]]=g[i]*g[prime[j]];
        }
    }
    for (int i=1;i<=maxn-50;i++) g[i]+=g[i-1];
}
int main()
{
    scanf("%d",&t);get_table();
    for (int i=1;i<=t;i++)
    {
        scanf("%d",&n);
        int l=1,r;
        long long ans=0;
        while (l<=n)
        {
            r=n/(n/l);
            ans+=(long long)(n/l)*(n/l)*(g[r]-g[l-1]);
            l=r+1;
        }
        printf("%lld\n",ans);
    }
    return 0;
}