[BZOJ 2818] Gcd

Link:https://www.lydsy.com/JudgeOnline/problem.php?id=2818

 

Algorithm:

一道比较水的数论题

可以发现只要找到所有素数,对于每个素数计算出1~n/p的互质的数的个数

一看到互质,联想到欧拉函数

预处理欧拉函数的前缀和,结果为sigma(pre[n/prime[i]]*2-1)  (有序数对,舍去(1,1)特解)

 

Code:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int MAXN=1e7+10;
bool mark[MAXN];
int n,prime[MAXN],phi[MAXN],cnt=0;
ll pre[MAXN],res=0;

void Getphi()
{
    phi[1]=1; //线性筛
    for(int i=2;i<=n;i++)
    {
        if(!mark[i]) prime[++cnt]=i,phi[i]=i-1;
        for(int j=1;j<=cnt;j++)
        {
            if(prime[j]*i>n) break;
            mark[prime[j]*i]=true;
            if(i%prime[j]==0){phi[i*prime[j]]=prime[j]*phi[i];break;}   //保证复杂度的关键
            else phi[i*prime[j]]=phi[i]*phi[prime[j]];
        }
    }
}

int main()
{
    cin >> n;
    Getphi();
    
    for(int i=1;i<=n;i++)
        pre[i]=pre[i-1]+phi[i];
    for(int i=1;i<=cnt;i++)
        res+=pre[n/prime[i]]*2-1;
    cout << res;
    return 0;
}

 

Review:

1、互质数对数    ----->     欧拉函数

 

2、线性筛

其中i%prime[j]=0时break是保证复杂度的关键

这样才能保证每个合数都由自己最小的质因数更新 ( 证明:https://wenku.baidu.com/view/2d706761aa00b52acec7ca63.html )

 

同时线性筛和素数筛在筛的顺序上有差异,线性筛是先广度,素数筛是先深度(原因在于phi[i]要先求出)

 

posted @ 2018-05-17 13:29  NewErA  阅读(141)  评论(0编辑  收藏  举报