• 【codeforces 870F】Paths


    Description

    You are given a positive integer n. Let's build a graph on vertices 1, 2, ..., n in such a way that there is an edge between vertices u and v if and only if gcd(u,v)≠1. Let d(u, v) be the shortest distance between u and v, or 0 if there is no path between them. Compute the sum of values d(u, v) over all 1 ≤ u < v ≤ n.The gcd (greatest common divisor) of two positive integers is the maximum positive integer that divides both of the integers.

    Input

    Single integer n (1 ≤ n ≤ 107).

    Output

    Print the sum of d(u, v) over all 1 ≤ u < v ≤ n.

    Examples

    input
    6
    output
    8
    input
    10
    output
    44

    Note

    All shortest paths in the first example:

    There are no paths between other pairs of vertices.The total distance is 2 + 1 + 1 + 2 + 1 + 1 = 8. 

    题意:
    给定数字n,建立一个无向图。对于所有1~n之间的数字,当数字gcd(u,v)≠1时将u、v连一条边,边权为1。d(u, v)表示u到v的最短路,求所有d(u, v)的和,其中1 ≤ u < v ≤ n。
     
    分析:
    对于1以及所有大于n/2的的质数,与其他数字均不联通,直接剔除。
    对于剩下的数字:
    1.当gcd(u,v)≠1时,d(u, v)==1。即对于数字u,小于u且d(u, v)==1的数字个数为x - 1 - φ(x)。
    2.令p[u]表示数字u的最小质因子,则当p[u]·p[v] ≤ n时,d(u, v)==2。维护数组num、sum,num[i]代表最小质因子为i的数字个数,sum数组为num数组的前缀和。统计Σnum[i]·sum[n/i]可以覆盖所有p[u]·p[v] ≤ n的情况,其中减去自身与自身被统计的情况,剩下的所有数对都被统计了两次,其中包含gcd(u,v)≠1的情况,需进行相应处理,详见代码。
    3.剩下的数对最短路一定为3,因为 u→2·p[u]→2·p[v]→v这条路一定存在。可通过数对总数减去d(u, v)==1与d(u, v)==2的情况得到。
     
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define LL long long
     5 using namespace std;
     6 const int N=1e7+5;
     7 int n,m,tot,now,pri[N],p[N],phi[N],num[N],sum[N]; 
     8 LL one,two,three;
     9 int main()
    10 {
    11     scanf("%d",&n);
    12     phi[1]=1;
    13     for(int i=2;i<=n;i++)
    14     {
    15         if(!p[i]){p[i]=pri[++tot]=i;phi[i]=i-1;}
    16         for(int j=1;j<=tot;j++)
    17         {
    18             if(i*pri[j]>n)break;
    19             p[i*pri[j]]=pri[j];
    20             if(i%pri[j]==0){phi[i*pri[j]]=phi[i]*pri[j];break;}
    21             else phi[i*pri[j]]=phi[i]*(pri[j]-1);
    22         }
    23     } 
    24     for(int i=2;i<=n;i++)one+=i-1-phi[i];
    25     for(int i=2;i<=n;i++)num[p[i]]++;
    26     for(int i=2;i<=n;i++)sum[i]=sum[i-1]+num[i];
    27     for(int i=2;i<=n;i++)two+=1ll*num[i]*sum[n/i];
    28     for(int i=2;i<=n;i++)if(1ll*p[i]*p[i]<=n)two--;
    29     two=two/2-one;m=n-1;
    30     for(int i=tot;i>=1;i--)
    31         if(pri[i]*2>n)m--;
    32         else break;
    33     three=1ll*m*(m-1)/2-one-two;
    34     printf("%I64d
    ",one+two*2+three*3);
    35     return 0;
    36 }
    View Code
  • 相关阅读:
    FastDFS学习总结(2)--Tracker与Storage配置详解
    FastDFS学习总结(1)--FastDFS安装和部署
    Git学习总结(6)——作为一名程序员这些代码托管工具你都知道吗?
    Git学习总结(6)——作为一名程序员这些代码托管工具你都知道吗?
    ActiveMQ学习总结(8)——消息队列设计精要
    ActiveMQ学习总结(8)——消息队列设计精要
    vnc
    Apache HTTP服务器 2.0版本文档
    SSH登录很慢
    source insight技巧
  • 原文地址:https://www.cnblogs.com/zsnuo/p/8257993.html
Copyright © 2020-2023  润新知