GCD

GCD

\(\sum_{i=1}^n\sum_{j=1}^n(gcd(i,j)\in prime)\),\(n\leq 10^9\)

法一:Mobius反演

\[ans=\sum_{i=1}^n\sum_{j=1}^n(gcd(i,j)\in prime) \]

\[=\sum_{p\in prime}\sum_{i=1}^n\sum_{j=1}^n(gcd(i,j)==p)= \]

\[f(k)=\sum_{i=1}^n\sum_{j=1}^n(gcd(i,j)==k) \]

\[F(k)=[n/k]^2 \]

由Mobius反演定理,我们有

\[f(k)=\sum_{k|d}[n/d]^2\mu(d/k) \]

代入,有

\[ans=\sum_{p\in prime}\sum_{p|d}[n/d]^2\mu(d/p)= \]

\[=\sum_{d=1}^n[n/d]^2\sum_{p|d}\mu(d/p) \]

显然后式可以\(O(nlog(n))\)维护,而前式可以整除分块,于是问题解决。

参考代码

暂缺

法二:初等数论

\(\sum\)一定要拆开来看,枚举一个质数p,时间复杂度我们是能够接受的,于是对于其中一个枚举项i,能满足条件的必然1-n间与之gcd为p的数的个数,该枚举范围为\([n/p]\),也就是这个范围内与i互质的数的个数,显然想到欧拉函数,于是对于一个质数p所对答案的贡献为\(\sum_{i=1}^{[n/p]}2\varphi(i)-1\),之所以乘以2,原因在于统计的是二元组,减去1是防止gcd(1,1)重复,于是维护出欧拉函数前缀和,直接枚举质数即可。

参考代码:

#include <iostream>
#include <cstdio>
#define il inline
#define ri register
#define ll long long
#define SIZE 10000000
using namespace std;
ll phi[SIZE+1];
bool check[SIZE+1];
int prime[1000000],pt;
il void prepare(int);
int main(){
    int n,i;scanf("%d",&n);
    prepare(n);ll ans(0);
    for(i=1;i<=pt;++i)ans+=phi[n/prime[i]]*2-1;
    printf("%lld",ans);
    return 0;
}
il void prepare(int n){
    ri int i,j;phi[1]=1;
    for(i=2;i<=n;++i){
        if(!check[i])prime[++pt]=i,phi[i]=i-1;
        for(j=1;j<=pt&&prime[j]*i<=n;++j){
            check[i*prime[j]]|=true;
            if(!(i%prime[j])){
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            phi[i*prime[j]]=phi[i]*phi[prime[j]];
        }
    }for(i=1;i<=n;++i)phi[i]+=phi[i-1];
}

posted @ 2019-05-16 12:46  a1b3c7d9  阅读(163)  评论(4编辑  收藏  举报