欧拉 uva 11426 - GCD - Extreme (II)

本文介绍了一种高效计算特定GCD表达式之和的方法。对于给定的正整数n,通过预处理phi函数及f[n]值,利用前缀和技巧,实现了快速求解GCD(i,j)(i<j≤n)的所有组合之和。

题意:(详见蓝皮书P125)

给定正整数n,求下列表达式的值:

G =
i<N     j<=N
GCD(i, j)
i=1     j=i+1

Input

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

Output

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

Sample Input

10

100

2000000

Sample Output

67

13015

143295493160

分析:

记f[n]= ∑gcd(i,n)     (1<=i<=n) ,那么所求就是f[1]+f[2]+......+f[n]=sum[n];

那么怎么求f[n]呢?

设d=gcd(x,n),显然d为n的因数,

那么 gcd(x/d,n/d)==1;   (*)

根据phi的定义,(*)式有 phi(n/d)个解,那么这一种情况的解的和 就是 d*phi(n/d);

这样用逐个分解因数的方法求一个f[n]的时间复杂度为n^(1/2),显然会TLE。

可以模拟筛法求phi的过程求出f[n]。

注意使用 long long

代码如下:

// by spark 2016/5/21 Friday 23:50
#include<cstdio>
#include<iostream>
#define LL long long
using namespace std;
const int maxn=4000000+5;
int phi[maxn];
LL sum[maxn],f[maxn];
void phi_table(int n){
	int i,j;
	for(i=1;i<=n;i++)phi[i]=i;
	for(i=2;i<=n;i++){
		if(phi[i]==i)
			for(j=i;j<=n;j+=i)
				phi[j]=phi[j]/i*(i-1);
	}
}
void f_table(int n){
	int i,j;
	for(i=1;i<=n;i++)
		for(j=i+i;j<=n;j+=i)
			f[j]+=i*phi[j/i];
}
int main(){
	int n,i;
	phi_table(maxn);   //打出phi表 
	f_table(maxn);    //计算f 
	for(i=1;i<=maxn;i++)
		sum[i]=sum[i-1]+f[i];    //前缀和 
	while(true){
		cin>>n;
		if(!n) return 0;
		cout<<sum[n]<<endl;
	}
	return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值