題目
定義F(n)表示最小公倍數爲n的二元組的數量。
即:如果存在兩個數(二元組)X,Y(X <= Y),它們的最小公倍數爲N,則F(n)的計數加1。
例如:F(6) = 5,因爲[2,3] [1,6] [2,6] [3,6] [6,6]的最小公倍數等於6。
給出一個區間[a,b],求最小公倍數在這個區間的不同二元組的數量。
例如:a = 4,b = 6。符合條件的二元組包括:
[1,4] [2,4] [4,4] [1,5] [5,5] [2,3] [1,6] [2,6] [3,6] [6,6],共10組不同的組合。
Input
輸入數據包括2個數:a, b,中間用空格分隔(1 <= a <= b <= 10^11)。
Output
輸出最小公倍數在這個區間的不同二元組的數量。
Input示例
4 6
Output示例
10
思路
最近做了一道杜教篩的題,來練手
反演+杜教篩
代碼
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int mxn=1000010;
int pri[mxn],mu[mxn],cnt=0;
bool vis[mxn];
void init(){
mu[1]=1;
for(int i=2;i<mxn;i++){
if(!vis[i]){
pri[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt && pri[j]*i<mxn;j++){
vis[pri[j]*i]=1;
if(i%pri[j]==0){mu[pri[j]*i]=0;break;}
mu[pri[j]*i]=-mu[i];
}
}
return;
}
LL calc(LL n){
if(!n)return 0;
LL i,j,k,ed=floor(sqrt(n));
LL res=0,tmp=0;
for(k=1;k<=ed;k++){
if(mu[k]){
tmp=0;
LL ED=n/(k*k);
for(i=1;i*i*i<=ED;i++){
for(j=i+1;j*j*i<=ED;j++)
tmp+=(ED/(i*j)-j)*6+3;
tmp+=(ED/(i*i)-i)*3;
tmp++;
}
res+=mu[k]*tmp;
}
}
return (res+n)/2;
}
LL a,b;
int main(){
init();
scanf("%lld%lld",&a,&b);
printf("%lld\n",calc(b)-calc(a-1));
return 0;
}