• [二分] Codeforces 1271E Common Number


    题目链接

    题解

    容易发现,对于给定的(N),假设(y)(k)个互异的(path_j)中出现,那么在([1,n])内一定存在且只存在(k)个数,这(k)个数的二进制以(y)的二进制为前缀,或者若(y)的二进制最低位为(0)时,(y)的最低位也可进(1),然后再以(y)为前缀。

    不妨令(Judge(x))表示在([1,N])内以(x)的二进制为前缀的数的数量,即出现过(x)的互异的(path_j)的数量。那么我们从(x=1)开始,不断地将(x)左移,直到(Judge(x) < K),即可获得(Ans)的二进制最大长度。然后我们在这个(x)的基础上,从(x)的二进制高位到低位不断地尝试把(0)变成(1),若改变后(Judge(x))仍大于(K),则保持改变,否则继续判断下一位。

    对于函数(Judge(x)),我们按在(x)后添加的二进制位数分开计算,假设现在我们要在(x)后添加一个长为(Len)的后缀,我们可以用二分算出长为(Len)的最大的后缀,即为在(x)后添加长度为(Len)的后缀时,([1,N])中前缀为(x)的数的数量。

    Code

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    
    #define RG register int
    #define LL long long
    
    LL N,K;
    
    inline LL f(LL x,LL Len){
        LL L=0,R,Res=0;
        if(x&1) R=(1LL<<Len)-1;
        else R=(1LL<<(Len+1))-1;
        x<<=Len;
        if(x>N) return 0;
        while(L<=R){
            LL mid=(L+R)>>1;
            if(x+mid<=N){Res=mid+1;L=mid+1;}
            else R=mid-1;
        }
        return Res;
    }
    
    bool Judge(LL x){
        LL temp=x,Res=0,Len=0;
        while(temp<=N){Res+=f(x,Len);++Len;temp<<=1;}
        if(Res>=K) return true;
        return false;
    }
    
    inline LL GetLen(LL x){
        LL Len=0;
        while(x){++Len;x>>=1;}
        return Len-1LL;
    }
    
    int main(){
        cin>>N>>K;
        LL Ans=1;
        while(Judge(Ans<<1)) Ans<<=1;
        LL Len=GetLen(Ans);
        for(RG i=Len-1;i>=0;--i)
            if(Judge(Ans+(1LL<<i))) Ans+=(1LL<<i);
        cout<<Ans<<endl;
        return 0;
    }
    
  • 相关阅读:
    Memcached 分布式缓存系统部署与调试
    nginx_笔记分享_php-fpm详解
    nginx_笔记分享_配置篇
    linux定时任务crond那些事!
    命令passwd报错因inode节点处理记录
    linux下定时任务
    linux内核堆栈
    c语言之单链表的创建及排序
    c语言常见的几种排序方法总结
    Tiny4412之外部中断
  • 原文地址:https://www.cnblogs.com/AEMShana/p/12431440.html
Copyright © 2020-2023  润新知