题意
输入正整数n,求 gcd(1,2)+gcd(1,3)+gcd(2,3)+...+gcd(n−1,n), g c d ( 1 , 2 ) + g c d ( 1 , 3 ) + g c d ( 2 , 3 ) + . . . + g c d ( n − 1 , n ) , 即求所有满足 1≤i<j≤n 1 ≤ i < j ≤ n 的数对 (i,j) ( i , j ) 所对应的 gcd(i,j) g c d ( i , j ) 之和。分析
设 f(n)=gcd(1,n)+gcd(2,n)+gcd(3,n)+...+gcd(n−1,n), f ( n ) = g c d ( 1 , n ) + g c d ( 2 , n ) + g c d ( 3 , n ) + . . . + g c d ( n − 1 , n ) , 则答案为 S(n)=f(2)+f(3)+...+f(n),则S(n)=S(n−1)+f(n) S ( n ) = f ( 2 ) + f ( 3 ) + . . . + f ( n ) , 则 S ( n ) = S ( n − 1 ) + f ( n ) 。
用 g(n,i) g ( n , i ) 表示满足 gcd(x,n)=i且x<n g c d ( x , n ) = i 且 x < n 的正整数 x x 的个数,则
若依次计算 f(n) f ( n ) ,速度较慢,但可以逆向思维,对每个 i i 枚举它的倍数(并更新 f(n) f ( n ) 的值),时间复杂度与素数筛法一样。代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e6+2;
ll s[maxn],f[maxn];
int n;
int p[maxn+10]={0};
void init()
{
int i,j;
for(i=1; i<=maxn; i++) p[i]=i;
for(i=2; i<=maxn; i+=2) p[i]/=2;
for(i=3; i<=maxn; i+=2)
if(p[i]==i){
for(j=i; j<=maxn; j+=i)
p[j]=p[j]/i*(i-1);
}
}
int main()
{
init();
memset(f,0,sizeof(f));
for(int i=1;i<=maxn;++i)
for(int n=i+i;n<=maxn;n+=i)
f[n]+=i*p[n/i];
s[2]=f[2];
for(int i=3;i<=maxn;++i)
s[i]=s[i-1]+f[i];
while(scanf("%d",&n),n)
printf("%lld\n",s[n]);
return 0;
}