• P4318 完全平方数 [二分答案+容斥+莫比乌斯函数]


    完全平方数


    Descriptionmathcal{Description}
    小 X 自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而这丝毫不影响他对其他数的热爱。

    这天是小X的生日,小 W 想送一个数给他作为生日礼物。当然他不能送一个小X讨厌的数。他列出了所有小X不讨厌的数,然后选取了第 K个数送给了小X。小X很开心地收下了。

    然而现在小 W 却记不起送给小X的是哪个数了。你能帮他一下吗?

    TT 组数据, 每组数据的 K<=109K<=10^9, T<=50T<=50 .


    最初想法
    一个 完全平方数 的倍数分解质因数后, 存在有幂数大于11的质因子 .
    所以一个合法的数字必定是由若干个不同的质数相乘得来的.

    思维断点: 怎么算出第 KK 个合法的数 ?


    正解部分
    答案具有 单调性, 考虑 二分答案 ,
    要解决的问题为: [1,x][1,x] 内有多少个合法的数,

    设在 [1,x][1,x]TmpTmp 个合法的数,
    Tmp=x(x22+x32+ )+(x(23)2+x(35)2+ )Tmp=x-(frac{x}{2^2}+frac{x}{3^2}+cdots) + (frac{x}{(2 * 3)^2}+frac{x}{(3 * 5)^2}+cdots)-cdots

    设这个式子中的某一项分母为 t2t^2, 则 t[1,x]t∈[1,sqrt{x}], 且 tt 是由若干个不同的质数构成的.
    根据 莫比乌斯函数 的性质, 没有学过的可以看 这里 ,

    • μ(t)=1mu(t)=1, tt是由偶数个质数构成的, 该项为正 .
    • μ(t)=1mu(t)=-1, tt是由奇数个质数构成的, 该项为负 .

    于是 Tmp=i=1xμ(i)xi2Tmp=sum_{i=1}^{sqrt{x}}mu(i)lfloor frac{x}{i^2} floor
    问题得以解决.

    时间复杂度 O(xlogx)O(sqrt{x}logx), 其中 xmax=1010x_{max}=10^{10}


    实现部分
    二分的上界为 K10K*10 (能开多大开多大…) .
    但是记得开 long longlong long

    #include<cmath>
    #include<cstdio>
    #define reg register
    typedef long long ll;
    
    const int maxn = 1e6 + 100;
    
    int p_cnt;
    int p[maxn];
    int mu[maxn];
    
    bool is_p[maxn];
    
    void sieve(){
            p_cnt = 0, mu[1] = 1;
            for(reg int i = 2; i < maxn; i ++){
                    if(!is_p[i]) p[++ p_cnt] = i, mu[i] = -1;
                    for(reg int j = 1; j <= p_cnt && p[j]*i < maxn; j ++){
                            int t = p[j] * i;
                            is_p[t] = 1;
                            if(i % p[j] == 0){ mu[t] = 0; break ; }
                            mu[t] = -mu[i];
                    }
            }
    }
    
    ll Calc(ll mid){
            ll lim = sqrt(mid);
            ll s = 0;
            for(reg ll i = 1; i <= lim; i ++) s += mu[i] * (mid/i/i);
            return s;
    }
    
    void Work(){
            ll K;
            scanf("%lld", &K);
            ll l = 1, r = K*10;
            while(l < r){
                    ll mid = l+r >> 1;
                    if(Calc(mid) >= K) r = mid;
                    else l = mid + 1;
            }
            printf("%lld
    ", r);
    }
    
    int main(){
    //        freopen("a.in", "r", stdin);
    //        freopen("a.out", "w", stdout);
            sieve();
            int T;
            scanf("%d", &T);
            while(T --) Work();
            return 0;
    }
    
    
  • 相关阅读:
    SQL的四种连接-左外连接、右外连接、内连接、全连接
    查看Linux下端口占用情况的命令
    linux的命令(1)
    xsheell的下载安装初级使用
    日交易,根据权重分配流量的算法,根据权重和交易笔数
    根据权重挑选通道的简单算法
    Java中的String与常量池
    JAVA虚拟机内存分配与回收机制
    JVM 内部运行线程介绍
    AspectJ切入点语法详解
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822560.html
Copyright © 2020-2023  润新知