zoukankan      html  css  js  c++  java
  • GCD(洛谷 2568)

    题目描述

    给定整数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



     由题意得gcd(x,y)=p(这里我们假设p为一个已知的质数),并且下面的过程都在这个条件下进行,我们不妨设x<=y<=n

    x=a*py=b*p,则有gcd(a,b)=1,且1<=a,b<=n/p。同样不妨设a<=b(☚什么情况下会等于后面有讲到)。

    那么满足gcd(x,y)=p的数对(x,y)个数其实就是满足gcd(a,b)=1的数对个数(a,b)。(下面用num(x,y)来表示满足gcd(x,y)=p的数对(x,y)个数,num(a,b)同理)

    对于b来说,b的取值范围是1~n/p,而a的取值可以是φ(b)中的任意一个,所以num(x,y)=num(a,b)=∑φ(b)(b∈[1,n/p]),简单来说,就是1~n/p中所有数的欧拉函数值的和


     好,代码已经成功一大半了,但是现在我们并没有p的准确值,p可能是1~n中的任意一个质数。所以我们可以在预处理中先把1~n中的质数(p1、p2……)全部找出来,最后一一枚举这些质数,每枚举一个p,就处理 当gcd(x,y)等于此时的p 的时候的num(x,y),加到最后输出的结果ans中

    代码实现首先,我们用线性筛法求出1~n中每个数的欧拉函数值,用一个数组sum(注意要开long long)来存欧拉函数值的前缀和,方便后面查找值。

    其实可以这样理解,sum[i]存的就是1~i中所有数的欧拉函数值的和,也就是上面讲到的num(x,y)

    那么最后枚举1~n中的质数,每一次循环都得到了一个n/p值,即b的上界,那么此时的sum[n/p]*2-1就是满足gcd(x,y)=p的(x,y)的对数。

    解释一下:由样例可得,(2,4)和(4,2)是不同的两种答案,所以x,y可以交换位置得到一个新的答案,所以sum[n/p]要*2,;但是当a=b=1,即x=y=p时,只有一种答案,所以sum[n/p]*2需要再-1,将重复的删去。

     1 #include<bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 const int N=10000005;
     5 int n;
     6 ll sum[N],vis[N],p[N],phi[N];
     7 int main()
     8 {
     9     scanf("%d",&n);
    10     memset(vis,1,sizeof(vis));
    11     vis[0]=vis[1]=false;
    12     phi[1]=1;
    13     for(int i=2;i<=n;i++)
    14     {
    15         if(vis[i])p[++p[0]]=i,phi[i]=i-1;//记得找出质数
    16         for(int j=1;j<=p[0]&&p[j]*i<=n;j++)
    17         {
    18             vis[p[j]*i]=false;
    19             if(i%p[j])phi[i*p[j]]=phi[p[j]]*phi[i];
    20             else 
    21             {
    22                 phi[i*p[j]]=p[j]*phi[i];
    23                 break;
    24             }
    25         }//线性筛法
    26     }
    27     for(int i=1;i<=n;i++)sum[i]=sum[i-1]+phi[i];//前缀和
    28     ll ans=0;
    29     for(int i=1;i<=p[0]&&p[i]<=n;i++)//枚举1~n中的所有质数
    30         ans+=(sum[n/p[i]]<<1)-1;//sum[n/p]*2-1
    31     printf("%lld",ans);
    32     return 0;
    33 }
    View Code

    写这篇题解的时候思维比较混乱,我都不知道该如何组织语言了,花了超长时间的!希望能让你理解吧OvO

    如果可以的话,给个“推荐”资瓷一下吧(*^▽^*)

    //参考:zhou_yk 的博客

  • 相关阅读:
    Eclipse快捷键大全(转载)
    IE9浏览Flash页面时显示错位并不停地闪烁
    flash全屏事件和键盘按下事件部分不能触发问题
    AS3摘要(转载)
    【as3手册小记】ActionScript 中处理全屏模式的注意事项
    巧用FlashPaper 让Word文档变Flash
    AS3视频照相截图(转载)
    Json串到json对象的转换
    映射文件详解(转)
    Jquery .ajax方法分析(一)
  • 原文地址:https://www.cnblogs.com/ljy-endl/p/11409675.html
Copyright © 2011-2022 走看看