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

来源:互联网 发布:非凡网络加速器 编辑:程序博客网 时间:2024/05/18 02:14

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);    }}
0 0
原创粉丝点击