[bzoj2818]Gcd 欧拉函数

题目链接:bzoj2818

—————————————-

概述

题目大意如下。
给定一个正整数n,求满足 1x,yn ,且 gcd(x,y) 为质数的数对 (x,y) 有多少个。( 1n10000000

注:数对 (2,4) 和数对 (4,2) 是不同的数对.

—————————————-

题解

记答案为Ans,那么有:

Ans=i=1nj=1n[(k=2gcd(i,j)[gcd(k,gcd(i,j))=1])=1].

假如我们要对上面那个式子进行化简,那么抱歉,我是没有那么高的水平。那怎么解决这个问题呢?

我们不妨换个角度思考,既然题目想统计的是 gcd(x,y) 为质数的数对,那么我们可以枚举1~n之间的每一个质数 pi ,分别计算每个 pi 的贡献,也就是计算每个 pi 是多少对数的最大公约数。

我们假设 ab 的最大公约数是质数 p ,那么我们可以把ab写成这样的形式:

a=p×a1, b=p×b1.

其中, a1 b1 一定互质,否则 a b的最大公约数就不是 p 了。
由于我们枚举的是p,所以已经确定了 p ,故我们只要统计有多少对a1b1互质就能知道每个 p 有多少贡献了。

由于ab的取值范围是1~ n ,所以a1b1的取值范围均是1~ np ,我们可以枚举 a1 ,计算1~ a1 中有多少个数与 a1 互质即可,也就是:

i=1npj=1i[gcd(i,j)=1]=i=1npφ(i).

我们可以通过线性筛求得1~ n 中所有数的欧拉函数,记录前缀和来求得上式的值。

由于题目里的规定:(4,2) (2,4) 是不同数对,所以我们需要将这样统计的结果乘2。

还有一个细节需要注意:数对 (pi,pi) 的最大公约数也是 pi ,上面所给的计算式中将结果乘了2,也就是将数对 (x,y) 交换位置变成 (y,x) 。然而 (pi,pi) 交换之后还是 (pi,pi) ,所以需要将这一部分多计算的答案减去,也就是减去1~n之间质数的个数。

综上:

Ans=(2×i=1totj=1npiφ(j))tot.

—————————————-

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define ll long long
#define For(i,j,k) for(register int i=j; i<=(int)k; ++i)
#define Forr(i,j,k) for(register int i=j; i>=(int)k; --i)
#define INF 0x3f3f3f3f
using namespace std;

const int maxn = 10000005;

int n, tot;
int pri[maxn/10], phi[maxn];
ll Ans;
ll sum[maxn];
bool vis[maxn];

inline void init(int n){
    sum[1] = phi[1] = 1;
    For(i, 2, n){
        if(!vis[i]){
            pri[++tot] = i;
            phi[i] = i-1;
        }
        sum[i] = sum[i-1]+phi[i];//记录前缀和.
        for(register int j=1,x; j<=tot&&(x=i*pri[j])<=n; ++j){
            vis[x] = true;
            if(i%pri[j] == 0){
                phi[x] = phi[i]*pri[j];
                break;
            }
            else phi[x] = phi[i]*(pri[j]-1);
        }
    }
}//线性筛.

int main(){
    scanf("%d", &n);

    init(n);//线性筛求得质数及欧拉函数.
    Ans = 0;
    For(i, 1, tot)
        Ans += sum[n/pri[i]];//统计答案.
    Ans = (Ans<<1)-tot;//减去重复计算的部分.

    printf("%lld", Ans);
    return 0;
}

—————————————-

小结

本题难点在于概念转换,将统计数对贡献变成统计质数贡献,后者由于有更多的性质可以利用,比如可以转化成欧拉函数,所以更方便解题。

—————————————-

wrote by miraclejzd

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值