题意:(详见蓝皮书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;
}
本文介绍了一种高效计算特定GCD表达式之和的方法。对于给定的正整数n,通过预处理phi函数及f[n]值,利用前缀和技巧,实现了快速求解GCD(i,j)(i<j≤n)的所有组合之和。

被折叠的 条评论
为什么被折叠?



