洛谷P2568 GCD (欧拉函数/莫比乌斯反演)

P2568 GCD

题目描述

给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对.

输入输出格式

输入格式:

一个整数N

输出格式:

答案

输入输出样例

输入样例#1:

4

输出样例#1:

4

说明

对于样例\((2,2),(2,4),(3,3),(4,2)\)

\(1<=N<=10^7\)

来源:bzoj2818

本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作。

Solution

方法1:莫比乌斯反演,方法和yy的gcd一样
方法2:欧拉函数
题目就是要我们求

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

那么其实就是欧拉函数的的定义

欧拉函数\(\phi(i)\)即为i以内与i互质的数的个数

考虑对于一个质数\(p\),对于\(gcd(a,b)=p\)也就是\(gcd(x\times p,y\times p)=1\),那么对于\(1<=a,b<=\frac np\),一个质数\(p\)对答案的贡献就是

\[\sum_{i=1}^{\frac np}\phi(i) \]

那么线筛求一下欧拉函数顺便求一下前缀和就可以了
注意:因为(4,2),(2,4)这样的数对是算两个的,所以答案要\(\times\) 2,其次,我们是不会计算一个数本身是质数的情况的,所以还要加上\(n\)以内质数的个数
(顺便吐槽一句,还是莫比乌斯反演好用,真的难打)

Code

#include<bits/stdc++.h>
#define lol long long
#define il inline
#define rg register
#define Min(a,b) (a)<(b)?(a):(b)
#define Max(a,b) (a)>(b)?(a):(b)
#define NN 10000000

using namespace std;

const int N=1e7+10;
int n,tot;
lol phi[N],prime[N];
bool vis[N];

il void init() {
    for(rg int i=2;i<=n;i++) {
        if(!vis[i]) prime[++tot]=i,phi[i]=i-1;
        for(rg int j=1;j<=tot && i*prime[j]<=n;j++) {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0) {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            else phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
    for(rg int i=1;i<=n;i++) phi[i]+=phi[i-1];
}
int main()
{
    ios::sync_with_stdio(0);
    cin>>n; init(); lol ans=0;
    for(rg int i=1;i<=tot;i++) ans+=phi[n/prime[i]]*2;
    cout<<ans+tot<<endl;
}

博主蒟蒻,随意转载.但必须附上原文链接

http://www.cnblogs.com/real-l/

posted @ 2018-09-20 11:27  real_l  阅读(346)  评论(0编辑  收藏  举报