51nod1222 最小公倍数计数 莫比乌斯反演+组合计数

Posted ONION_CYC

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51nod1222 最小公倍数计数 莫比乌斯反演+组合计数相关的知识,希望对你有一定的参考价值。

【题意】给定a和b,求满足a<=lcm(x,y)<=b && x<y的数对(x,y)个数。a,b<=10^11。

【算法】莫比乌斯反演+组合计数

【题解】★具体推导过程参考51nod1222 最小公倍数计数

过程运用到的技巧:

1.将所有i和j的已知因子提取出来压缩上届。

2.将带有μ(k)的k提到最前面,从而后面变成单纯的三元组形式。

最终形式:

$$ans=\\sum_{k=1}^{\\sqrt n} \\mu(k)  \\sum_{d}    \\sum_{i} \\sum_{j} [i*j*d<=\\frac{n}{k^2}]$$

问题转化为枚举(d,i,j)三元组满足其乘积<=n/k^2。

虽然题目要求组合(有序),但是有d的存在,所以先求排列(无序)。

但是三元组的排列不方便统计,所以求三元组的组合乘上排列系数

先算严格从小到大的,然后减去两个相同的和三个相同的。

最后+n后/2就变成组合。

听说复杂度O(n^(2/3))。

#include<cstdio>
#include<cmath>
#define int long long
using namespace std;
const int maxn=1000010;
int miu[maxn],prime[maxn],tot;
bool vis[maxn];
int solve(int x){
    if(!x)return 0;
    int N=(int)sqrt(x)+1,ans=0;
    for(int k=1;k<=N;k++)if(miu[k]){
        int n=x/(k*k);
        for(int d=1;d*d*d<=n;d++){
            for(int i=d+1;i*i*d<=n;i++)ans+=miu[k]*((n/(d*i)-i)*6+3);
            ans+=miu[k]*((n/(d*d)-d)*3+1);
        }
    }
    return (ans+x)/2;
}    
#undef int
int main(){
#define int long long
    int A,B;
    scanf("%lld%lld",&A,&B);
    int N=(int)sqrt(B)+1;
    miu[1]=1;
    for(int i=2;i<=N;i++){
        if(!vis[i]){miu[prime[++tot]=i]=-1;}
        for(int j=1;j<=tot&&i*prime[j]<=N;j++){
            vis[i*prime[j]]=1;//
            if(i%prime[j]==0)break;
            miu[i*prime[j]]=-miu[i];
        }
    }
    printf("%lld\\n",solve(B)-solve(A-1));
    return 0;
}
View Code

 

以上是关于51nod1222 最小公倍数计数 莫比乌斯反演+组合计数的主要内容,如果未能解决你的问题,请参考以下文章

51nod1238. 最小公倍数之和 V3(莫比乌斯反演)

题解51Nod 1594 莫比乌斯反演

51Nod1675 序列变换 数论 莫比乌斯反演

51nod 1594 Gcd and Phi(莫比乌斯反演)

51nod1222 最小公倍数计数

51Nod 1237最大公约数之和 V3 莫比乌斯反演+杜教筛