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
  • 相关阅读:
    hive_case
    hive_group
    linux-搭建ngnix
    Nfs服务器搭建
    几种常见的启动脚本
    linux 修改本机的端口映射
    oracle-sql计算
    linux 磁盘大小查看
    postMan测试接口的几种方式
    oracle迁移到12c的时列转行 wm_concat 报错解决
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8490625.html
Copyright © 2011-2022 走看看