GCD Extreme 【FZU--1969】

本文探讨了一个算法问题,即计算从1到n的所有数对(i, j)的最大公约数之和,其中i < j <= n。通过引入f(n)函数,将问题简化并利用欧几里得算法解决最大公约数问题,最后给出实现该算法的代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

Given the value of N, you will have to find the value of G. The meaning of G is given in the following code

G=0;

for(i=1;i<=N;i++)

  for(j=i+1;j<=N;j++)

    G+=gcd(i,j);

/*Here gcd() is a function that finds the greatest common divisor of the two input numbers*/


题意:输入正整数n,求gcd(1,2)+gcd(1,3)+gcd(2,3)+...+gcd(n-1,n),即所有满足1<=i<j<=n的数对(i,j)所对应的gcd(i,j)之和。

分析(源自《算法竞赛入门经典训练指南》):

           设f(n)=gcd(1,n)+gcd(2,n)+...+gcd(n-1,n),则所求答案为S(n)=f(2)+f(3)+...+f(n)。只需求出f(n),就可以推出所有答案:S(n)=S(n-1)+f(n) 即 f(n)=f(n-1)+f(n)。因此,本题的重点在于如何计算f(n)

           注意到所有gcd(x,n)的值都是n的约数,可以按照这个约数进行分类,用g(n,i)表示满足gcd(x,n)=i且x<n的正整数x的个数,则f(n)=sum{i*g(n,i)|i是n的约数}。注意到gcd(x,n)=i的重要条件是gcd(x/i,n/i)=1,因此满足条件的x/i有 phi(n/i)个,说明g(n,i)=phi(n/i)。【phi(n)表示不超过n且和n互素的整数的个数】

           如果依次计算f(n),需要对每个n枚举它的约数i,速度较慢,但如果把思路逆过来,对于每个i枚举它的倍数n(并且更新f(n)的值),时间复杂度讲降为与素数筛法同阶。具体代码如下。


Input

The input file contains at most 20000 lines of inputs. Each line contains an integer N (1<N <1000001). The meaning of N is given in the problem statement. Input is terminated by a line containing a single zero.

Output

For each line of input produce one line of output. This line contains the value of G for the corresponding N. The value of G will fit in a 64-bit signed integer.

Sample Input

10

100

200000

0

Sample Output

67

13015

143295493160

<span style="font-size:18px;">#include <cstdio>
#include <algorithm>
#include <cstring>
const int maxn=1000101;
typedef long long LL;
using namespace std;
int phi[maxn+1];
void phi_table(int n)                           //用类似筛法的方法求phi[]数组
{
    memset(phi,0,sizeof(phi));
    phi[1]=1;
    for(int i=2; i<=n; i++)
        if(!phi[i])
            for(int j=i; j<=n; j+=i)
            {
                if(!phi[j])
                    phi[j]=j;
                phi[j]=phi[j]/i*(i-1);
            }
}
LL f[maxn+1];
int main()
{
    phi_table(maxn);
    memset(f,0,sizeof(f));
    for(int i=1; i<=maxn; i++)
        for(int j=i*2; j<=maxn; j+=i)
            f[j]+=i*phi[j/i];
    for(int i=3; i<=maxn; i++)
        f[i]+=f[i-1];
    int n;
    while(~scanf("%d",&n)&&n)
        printf("%I64d\n",f[n]);
    return 0;
}</span>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值