[UVa 11426] GCD - Extreme (II) (数论 + 脑洞 + 技巧)

本文介绍了解决UVa-11426问题的方法,该问题要求计算所有数对(i,j)的gcd(i,j)之和,其中i和j不超过给定的N值。通过枚举gcd并利用欧拉函数φ来计算每个数作为gcd出现的次数,最终实现了高效求解。

UVa - 11426

给定一个 N,数对 i,j <= N且 i < j
求所有数对的 gcd(i,j)的和
其中 N <= 4e6


这是大白 p125的例题
首先按题目描述两个for肯定是不行的
所以我们反过来考虑,一个数是多少对数的gcd
换句话来说,就是一个数被加了几次
于是我们枚举这个gcdi
设有数对 aba<b使得 gcd(a,b)=i
a=aib=bi
其中ab互质且 a<b
那么对于一个b,小于他的数有多少个与它互质呢
答案是 ϕ(b)
于是我们就能得到对于一个数b,有多少个a使得 gcd(a,b)=i
时间复杂度O(N(ln(n)+C)),其中C是欧拉常数
所以问题就得到解决了

关于一个数的因子或gcd,通过枚举因子来计算通常比分解一个数来得更方便

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef pair<int,int> Pii;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DBL;
typedef long double LDBL;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Pow2(a) (a*a)

const int maxn=4e6+10;;
int N;
int phi[maxn];
LL sum[maxn],ans[maxn];

void init_phi(int);

int main()
{
    init_phi(maxn);
    for(int i=1; i<maxn; i++) for(int j=i*2; j<maxn; j+=i)
        sum[j]+=(LL)i*phi[j/i];
    ans[2]=sum[2];
    for(int i=3; i<maxn; i++) ans[i]=ans[i-1]+sum[i];
    while(~scanf("%d", &N)&&N)
    {
        printf("%lld\n", ans[N]);
    }
    return 0;
}

void init_phi(int Lim)
{
    for(int i=1; i<Lim; i++) phi[i]=i;
    for(int i=2; i<Lim; i++)
    {
        if(phi[i]<i) continue;
        for(int j=i; j<Lim; j+=i) phi[j]=phi[j]/i*(i-1);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值