[51nod 1222]最小公倍數計數

題目

定義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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章