題目大意:給出
我們首先令
又因爲
所以
不妨設
即我們的問題現在轉化爲求有多少對三元組
使得 i ( i + j ) k <= N && j ( i + j ) k <= N && gcd ( i , j ) == 1
若是枚舉
對於
我們會發現
有一部分
相同的
於是這裏有一個神奇的做法:我們不妨枚舉
初始化
那麼我們可以說
至於上面說的神奇的方法,
可以理解爲 本來 N 除以
i 還有增長的區間,除了兩次後,
這時下個區間就是
至於在當前區間內有多少個
具體細節可以看代碼:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;
#define MAXN 50000
#define MAXM
#define INF 0x3f3f3f3f
typedef long long int LL;
void Read(LL &x){
x=0;char c=getchar();bool flag=0;
while(c<'0'||'9'<c){if(c=='-')flag=1;c=getchar();}
while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
if(flag)x=-x;
}
int u[MAXN+10];
bool isprime[MAXN+10];
int prime[MAXN+10],Cnt;
void init(int n){
memset(isprime,1,sizeof(isprime));
Cnt=0;
n=sqrt(n);
u[1]=1;
for(int i=2;i<=n;++i){
if(isprime[i]){
prime[++Cnt]=i;
u[i]=-1;
}
for(int j=1;j<=Cnt&&i*prime[j]<=n;++j){
isprime[i*prime[j]]=0;
if(i%prime[j])
u[i*prime[j]]=-u[i];
else{
u[i*prime[j]]=0;
break;
}
}
}
}
int num[MAXN+10],top;
void Get_Divisor(LL n){
LL i;
top=0;
for(i=1;i*i<n;i++)
if(n%i==0)num[++top]=i,num[++top]=n/i;
if(i*i==n)num[++top]=i;
sort(num+1,num+top+1);
}
int main(){
LL N;
Read(N);
init(N);
LL i,j,k,last=0;
LL cnt=0;
LL ans=0;
for(j=1;j*(j+1)<=N;++j){
Get_Divisor(j);
for(i=1;i<j&&j*(i+j)<=N;i=last+1){
last=min(N/(N/j/(i+j))/j-j,j-1);
cnt=0;
for(k=1;num[k]<=last;++k)
cnt+=u[num[k]]*(last/num[k]-(i-1)/num[k]);
ans+=N/j/(i+j)*cnt;
}
}
printf("%lld\n",ans);
}