zoukankan      html  css  js  c++  java
  • 【51nod】1222 最小公倍数计数 莫比乌斯反演+组合计数

    【题意】给定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
    ",solve(B)-solve(A-1));
        return 0;
    }
    View Code
  • 相关阅读:
    go 基本包
    go 包
    算法笔记--数据结构--链表
    算法笔记--数据结构--队列
    算法笔记--标准模板库STL--pair
    算法笔记--标准模板库STL--stack
    算法笔记--标准模板库STL--priority_queue
    算法笔记--标准模板库STL--queue
    初识pair
    lower_bound实现离散化
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8490625.html
Copyright © 2011-2022 走看看