zoukankan      html  css  js  c++  java
  • BZOJ2818 Gcd

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

     

     

    本文作者:ljh2000
    作者博客:http://www.cnblogs.com/ljh2000-jump/
    转载请注明出处,侵权必究,保留最终解释权!

     

    Description

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

    Input

    一个整数N

    Output

    如题

    Sample Input

    4

    Sample Output

    4

    HINT


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

    1<=N<=10^7

    正解:线性筛+欧拉函数

    解题报告:

      考虑质数$p$的贡献就是$1$到$n/p$之间的互质对数。而对于$1$到$m$的互质对数,我们很容易发现只有当$a=b=1$时,两个数才有可能相等,那么我们只需要考虑$a<b$的情况。对于$b$,显然与$b$互质且小于$a$的个数就是$b$的欧拉函数。

      因而,我们就可以得到一个简单的做法:线性筛筛出质数,同时求出每个数的欧拉函数,并得到欧拉函数的前缀和。然后我们再枚举一个素数$p$,对于p的贡献就是$1$到$n/p$的欧拉函数前缀和$*2-1$(减$1$是因为$a=1、b=1$被算了两次),累加所有素数的贡献就是答案。

      值得注意的是,欧拉函数显然不是积性函数,开始我把欧拉函数当成积性函数做,$WA$了一发。欧拉函数满足如下性质:如果$i$ mod $p$ $!=0$,则$phi[i*p]=phi[i]*phi[p]$;否则$phi[i*p]=phi[i]*p$。这个式子就很方便我们在线性筛的时候递推了。

    //It is made by ljh2000
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <ctime>
    #include <vector>
    #include <queue>
    #include <map>
    #include <set>
    #include <string>
    using namespace std;
    typedef long long LL;
    const int MAXN = 10000011;
    const int MAXM = 5000011;
    int n,phi[MAXN],prime[MAXM],cnt;
    LL sum[MAXM],ans;
    bool vis[MAXN];
    
    inline int getint(){
        int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
        if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
    }
    
    inline void work(){
    	n=getint(); phi[1]=1; cnt=0; ans=0;
    	for(int i=2;i<=n;i++) {
    		if(!vis[i]) { phi[i]=i-1; prime[++cnt]=i; }
    		for(int j=1;j<=cnt && ((LL)i*prime[j]<=n);j++) {
    			vis[i*prime[j]]=1; 
    			//if(i%prime[j]==0) break;
    			//并非积性函数
    			if(i%prime[j]==0) { phi[i*prime[j]]=phi[i]*prime[j]; break; }
    			else phi[i*prime[j]]=phi[i]*phi[prime[j]];
    		}
    	}
    	for(int i=1;i<=5000000;i++) sum[i]=sum[i-1]+phi[i];
    	for(int i=1;i<=cnt;i++) ans+=2*sum[n/prime[i]]-1;
    	printf("%lld",ans);
    }
    
    int main()
    {
        work();
        return 0;
    }
    

      

  • 相关阅读:
    面向对象定义
    xml与面上对象初识
    模块configparser/subprocess/表格处理模块
    python模块
    python-判断语句
    python了解
    Qt Qwdget 汽车仪表知识点拆解7 图像绘制,旋转
    Qt Qwdget 汽车仪表知识点拆解6 自定义控件
    Qt Qwdget 汽车仪表知识点拆解5 标题栏图标闪烁
    Qt Qwdget 汽车仪表知识点拆解4 另类进度条实现
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6233791.html
Copyright © 2011-2022 走看看