zoukankan      html  css  js  c++  java
  • P2568 GCD

    P2568 GCD

    题意

    给定正整数(n),求(1leq x,yleq n)(gcd(x,y))为质数的数对((x,y))个数
    (1leq nleq 10^7)


    欧拉(varphi)函数的基础题,关于欧拉(varphi)函数
    所以基础知识就不在这篇里讲了

    把题目描述成公式,并且枚举每一个质数(p)

    [sum_{pin {prime}}sum_{x=1}^nsum_{y=1}^n [gcd(x,y)=p] ]

    然后做一步变形,这好像是(gcd)的常规操作

    [sum_{pin{prime}}sum_{x=1}^{lfloorfrac{n}{p} floor}sum_{y=1}^{lfloorfrac{n}{p} floor} [gcd(x,y)=1] ]

    上面这一步的意思大概就是,对于每一个(gcd(x,y)=p)((x,y)),都能找到一个(x',y',gcd(x',y')=1),使得(gcd(x'p,y'p)=p)
    那么,这些((x',y'))((x,y))一一对应,所以数量一样多,于是求((x,y))的个数就变成了求((x',y'))的个数
    然后又因为(x',y'leq lfloordfrac{n}{p} floor),所以只枚举到(lfloordfrac{n}{p} floor)就行了

    再继续变形,发现((x,y))是无序的,下面的((x,y))就默认说的是((x',y')),所以可以通过改变(y)的上限变成有序然后再乘(2)来算

    [sum_{pin{prime}}(sum_{x=1}^{lfloorfrac{n}{p} floor}(2 imes sum_{y=1}^x [gcd(x,y)=1])-1) ]

    要减(1)是因为((x,x))是不符合要求的,多算了一个,看清楚上面式子里的括号

    然后可以发现,最里面那个(sum)就是(varphi),所以可以变形成:

    [sum_{pin{prime}}((sum_{x=1}^{lfloorfrac{n}{p} floor}2varphi(x))-1) ]

    [sum_{pin{prime}}(2sum_{x=1}^{lfloorfrac{n}{p} floor}varphi(x)-1) ]

    所以我们只需要线性筛求出(varphi)再做个前缀和按公式算就行

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<iomanip>
    #include<cstring>
    #define reg register
    #define EN std::puts("")
    #define LL long long
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    int n;
    LL phi[10000006];
    int prime[1000006],notprime[10000006];
    inline void get_phi(){
    	phi[1]=1;
    	for(reg int i=2;i<=n;i++){
    		if(!notprime[i]) prime[++prime[0]]=i,phi[i]=i-1;
    		for(reg int j=1;j<=prime[0]&&i*prime[j]<=n;j++){
    			notprime[i*prime[j]]=1;
    			if(!(i%prime[j])){
    				//i mod p=0, phi(i*p)=p*phi(i)
    				phi[i*prime[j]]=prime[j]*phi[i];
    				break;
    			}
    			else phi[i*prime[j]]=phi[i]*(prime[j]-1);//i mod p!=0,phi(i*p)=phi(i)*(p-1)
    		}
    	}
    }
    int main(){
    	n=read();get_phi();
    	for(reg int i=2;i<=n;i++) phi[i]+=phi[i-1];
    	LL ans=0;
    	for(reg int i=1;i<=prime[0];i++) ans+=2*phi[n/prime[i]]-1;
    	std::printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    Golang 数组
    Golang 定时任务库使用
    Golang 选项设计模式
    使用阿里云构建海外docker镜像
    大数相加算法实现
    递归思想和迭代思想
    阶乘函数(factorial)——结果在整型范围内的阶乘计算
    最大公约数和最小公倍数(Greatest Common Divisor and Least Common Multiple)
    日结(2018年12月23日)
    日结(2018年12月22日)
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/12622668.html
Copyright © 2011-2022 走看看