luogu2568GCD题解--欧拉函数

题目链接

https://www.luogu.org/problemnew/show/P2568

分析

题目即求\(\sum_{i=1}^N \sum_{j=1}^N [gcd(i,j)\) \(is\) \(a\) \(prime\) \(number\) \(]\)

我们提出这个素数变成\(\sum_p \sum_{i=1}^{\frac{N}{p} \ } \sum_{j=1}^{\frac{N}{p} \ } [gcd(i,j)\) \(is\) \(1]\)

对于后面两个\(sigma\),考虑\(i>=j\)\(i<j\)两种情况,不难想到答案为\(2 * (\sum_{i=1}^{\frac {N}{P} \ }\phi(i))-1\),因为\(i=j=1\)时多算了种情况

于是求欧拉函数表同时前缀和就好了

代码

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cctype>
#include <iostream>
#define ll long long 
#define ri register int 
using std::min;
using std::max;
template <class T>inline void read(T &x){
    x=0;int ne=0;char c;
    while(!isdigit(c=getchar()))ne=c=='-';
    x=c-48;
    while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
    x=ne?-x:x;return ;
}
const int inf=0x7fffffff;
int pri[1000005],tot=0;
ll phi[10000007];
int n;
inline void get_phi(){
    bool vis[10000005];
    memset(vis,0,sizeof(vis));
    vis[1]=1,phi[1]=1;
    for(ri i=2;i<=n;i++){
        if(!vis[i]){pri[++tot]=i,phi[i]=i-1;}
        for(ri j=1;j<=tot&&pri[j]*i<=n;j++){
            vis[i*pri[j]]=1;
            if(i%pri[j]==0){phi[i*pri[j]]=phi[i]*pri[j];break;}//定义式,i*pri[j]与i的质因数是相同的 
            else phi[i*pri[j]]=phi[i]*phi[pri[j]];//积性函数 
        }
    }
    for(ri i=2;i<=n;i++)phi[i]+=phi[i-1];
    return ;
}
ll ans=0;
int main(){	
    read(n);
    get_phi();
    for(ri i=1;i<=tot&&pri[i]<=n;i++){
        ans+=(phi[n/pri[i]]<<1)-1;
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2018-09-14 18:42  Rye_Catcher  阅读(102)  评论(0编辑  收藏  举报