BZOJ 2818 Gcd 线性欧拉

题意:链接

方法:线性欧拉

解析:

首先列一下表达式

gcd(x,y)=z(z是素数并且x,y<=n).

然后我们可以得到什么呢?

gcd(x/z,y/z)=1;

不妨令y>=x

则可以得到我们要的答案就是∑max(y/z)i=1phi(i)

而max(y/z)就是max(n/z);

所以只需要枚举一下质数z随便搞一下就好了,最好用前缀和记录

HINT:前缀和写树状数组的都是(*)

代码:

正常人做法1.1s

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 10000010
using namespace std;
typedef long long ll;
int n,tot;
int prime[N];
int phi[N];
ll sum[N];
int f[N];
void sieve()
{
    phi[1]=1;
    sum[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!f[i])
        {
            prime[++tot]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=tot,i*prime[j]<=n;j++)
        {
            f[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]*phi[prime[j]];
            }
        }
        sum[i]=sum[i-1]+phi[i];
    }
}
int main()
{
    scanf("%d",&n);
    sieve();
    ll print=0;
    for(int i=1;i<=tot;i++)
    {
        int up=n/prime[i];
        print+=sum[up];
    }
    printf("%lld\n",print*2-tot);
}

树状数组4.8s

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 10000010
using namespace std;
typedef long long ll;
int n,tot;
int prime[N];
int phi[N];
ll sum[N];
int f[N];
int lowbit(int x){return x&(-x);}
void update(int x,int p)
{
    while(x<=n)
    {
        sum[x]+=p;
        x+=lowbit(x);
    }
}
ll getsum(int x)
{
    ll ret=0;
    while(x)
    {
        ret+=sum[x];
        x-=lowbit(x);
    }
    return ret;
}
void sieve()
{
    phi[1]=1;
    update(1,1);
    for(int i=2;i<=n;i++)
    {
        if(!f[i])
        {
            prime[++tot]=i;
            phi[i]=i-1;
            update(i,phi[i]);
        }
        for(int j=1;j<=tot,i*prime[j]<=n;j++)
        {
            f[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                update(i*prime[j],phi[i*prime[j]]);
                break;
            }else
            {
                phi[i*prime[j]]=phi[i]*phi[prime[j]];
                update(i*prime[j],phi[i*prime[j]]);
            }
        }
    }
}
int main()
{
    scanf("%d",&n);
    sieve();
    ll print=0;
    for(int i=1;i<=tot;i++)
    {
        int up=n/prime[i];
        print+=getsum(up);
    }
    printf("%lld\n",print*2-tot);
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-13 04:11:48

BZOJ 2818 Gcd 线性欧拉的相关文章

BZOJ 2818 Gcd 线性欧拉筛(Eratosthenes筛)

题目大意:给定整数N(N <= 1e7),求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对.. 思路:推一推. 设gcd(x,y) = p,则x / p与y / p互质 问题就转化成了N / p中有多少个数互质,然后累加就可以了. =>对于任意a,b,a <= N / p,b <= N / p,且a与b互质 =>gcd(a,b) == 1 现在问题就很明显了,看到这个形式就很容易想到欧拉函数,求一下phi,算一下前缀和,累加. 注意这里求欧拉一

bzoj 2818 gcd 线性欧拉函数

2818: Gcd Time Limit: 10 Sec  Memory Limit: 256 MB[Submit][Status][Discuss] Description 给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对. Input 一个整数N Output 如题 Sample Input 4 Sample Output 4 HINT hint 对于样例(2,2),(2,4),(3,3),(4,2) 1<=N<=10^7 思路:gcd(x,y)

bzoj 2818 GCD 数论 欧拉函数

bzoj[2818]Gcd Description 给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对. Input 一个整数N Output 如题 Sample Input 4 Sample Output 4 HINT hint对于样例(2,2),(2,4),(3,3),(4,2) 1<=N<=10^7 题解一(自己yy) phi[i]表示与x互质的数的个数 即gcd(x,y)=1 1<=y<x ∴对于x,y 若a为素数 则gcd(xa,

bzoj 2818 Gcd 【欧拉函数】

问题:求gcd(x,y)==质数, 1<=x,y<=n的有多少对? 做这题的时候,懂得了一个非常重要的转化:求(x, y) = k, 1 <= x, y <= n的对数等于求(x, y) = 1, 1 <= x, y <= n/k的对数!所以,枚举每个质数p,然后求(x, y) = 1, 1 <= x, y <= n/p的个数. (x, y) = 1 的个数如何求呢?欧拉函数! #include <stdio.h> #include <io

bzoj 2818 Gcd(欧拉函数)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2818 [题意] 问(x,y)为质数的有序点对的数目. [思路] 定义f[i]表示i之前(x,y)=1的有序点对的数目,则有递推式: f[1]=1 f[i]=f[i-1]+phi[i]*2 我们依次枚举小于n的所有素数,对于素数t,(x,y)=t的数目等于(x/t,y/t),即f[n/t]. [代码] 1 #include<cstdio> 2 #include<cstring&

【BZOJ】2818: Gcd(欧拉函数/莫比乌斯)

http://www.lydsy.com/JudgeOnline/problem.php?id=2818 我很sb的丢了原来做的一题上去.. 其实这题可以更简单.. 设 $$f[i]=1+2 \times \phi (i) $$ 那么答案就是 $$\sum_{p是质数} f[n/p]$$ 就丢原来的题了...不写了.. #include <cstdio> #include <cstring> #include <cmath> #include <string>

BNU 12846 LCM Extreme 最小公倍数之和(线性欧拉筛选+递推)

LCM Extreme Time Limit: 3000ms Memory Limit: 131072KB This problem will be judged on UVALive. Original ID: 596464-bit integer IO format: %lld      Java class name: Main Find the result of the following code:unsigned long long allPairLcm(int n){ unsig

uva 11317 - GCD+LCM(欧拉函数+log)

题目链接:uva 11317 - GCD+LCM 题目大意:给定n,求出1~n里面两两的最大公约的积GCD和最小公倍数的积LCM,在10100进制下的位数. 解题思路:在n的情况下,对于最大公约数为i的情况又phi[n/i]次.求LCM就用两两乘积除以GCD即可. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; ty

『素数(Prime)判定和线性欧拉筛法(The sieve of Euler)』

素数(Prime)及判定 定义 素数又称质数,一个大于1的自然数,除了1和它自身外,不能整除其他自然数的数叫做质数,否则称为合数. 1既不是素数也不是合数. 判定 如何判定一个数是否是素数呢?显然,我们可以枚举这个数的因数,如果存在除了它本身和1以外的因数,那么这个数就是素数. 在枚举时,有一个很简单的优化:一个合数\(n\)必有一个小于等于\(\sqrt{n}\)的因数. 证明如下: 假设一个合数\(n\)没有小于等于\(\sqrt{n}\)的因数. 由于\(n\)为合数,所以除了\(n\)与