[bzoj4804] 欧拉心算

[bzoj4804] 欧拉心算


莫比乌斯反演

自己的做法比较神奇

让s[x]表示phi的前缀和 ,f[x]表示1-n中gcd(i,j)=x的个数然后可以发现f[x]=s[n/x]*2-1 (这里是下取整)

然后就可以分块了

  • 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e7+1;
bool vis[N];
int prime[1000010],cnt;
ll phi[N];
inline void init(){
    phi[1]=1;
    for(int i=2;i<N;i++){
        if(!vis[i])prime[++cnt]=i,phi[i]=i-1;
        for(int j=1;j<=cnt;j++){
            if(i*prime[j]>=N)break;
            vis[i*prime[j]]=1;
            if(i%prime[j]){
                phi[i*prime[j]]=phi[i]*(prime[j]-1);
            }else{
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
        }
    }
    for(int i=2;i<N;i++)phi[i]+=phi[i-1];
}

inline void solve(int n){
    int u,v;
    ll ans=0;
    for(u=1;u<=n;u=v+1){
        v=n/(n/u);
        int w=n/u;
        ans+=(phi[w]*2-1)*(phi[v]-phi[u-1]);
    }
    printf("%lld\n",ans);
}

int main()
{
    init();
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        solve(n);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_35923186/article/details/82981510