zoukankan      html  css  js  c++  java
  • [机房测试] number

    Description

    给定 (mleq 10^18,kleq 64),求出一个正整数 (n) 使得 (n+1 sim 2n) 中恰好有 (m) 个数恰好有 (k)(1),以及有多少个这样的数。

    Solution

    考场上根本没什么思路。

    所以首先应该打个表,然后观察到 (f(i,k)) 表示 (i+1 sim 2i) 中恰有 (k)(1) 的数的个数是有单调性的,实际上也容易证明:

    [f(i+1,k)-f(i,k)=[popcount(2i+1)=k]+[popcount(2i+2)=k]-[popcount(i+1)=k] ]

    容易发现 (2i+2)(i+1)(popcount) 总是相等的,所以一定有 (f(i,k)) 关于 (i) 是单调不降的。那么就可以二分出一个 (i) 的上下界。

    (f(i,k)) 的值可以直接数位 dp 求出,注意特判 (k=1) 有无限种 (i) 的情况。

    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    
    typedef long long ll;
    
    inline ll read(){
        ll x=0,flag=1; char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
        return flag? x:-x;
    }
    
    bool a[64];
    int K,tp=0;
    ll dp[64][64];
    
    ll dfs(int st,int k,bool lim){
        if(st==63) return !k;
        if(!lim){
            ll &ret=dp[st][k];
            if(~ret) return ret; else ret=0;
            for(int i=0;i<2;i++)
                ret+=dfs(st+1,k-i,0);
            return ret;
        }else{
            ll ret=0;
            for(int i=0;i<=a[st];i++)
                ret+=dfs(st+1,k-i,i==a[st]);
            return ret;
        }
    }
    
    ll check(ll x){
        for(int i=0;i<63;i++) a[i]=(x>>(62-i))&1;
        reverse(a+1,a+1+tp); return dfs(1,K,1);
    }
    
    int main(){
        freopen("number.in","r",stdin);
        freopen("number.out","w",stdout);
        for(int i=0;i<64;i++)
            for(int j=0;j<64;j++) dp[i][j]=-1;
        int T=read();
        while(T--){
            ll m=read(); K=read();
            if(K==1)
                printf("2 -1
    ");
            else{
                ll l=1,r=2e18,L=2e18;
                while(l<=r){
                    ll mid=(l+r)>>1;
                    if(check(mid<<1)-check(mid)>=m)
                        L=mid,r=mid-1;
                    else l=mid+1;
                }
                l=1,r=2e18; ll R=1;
                while(l<=r){
                    ll mid=(l+r)>>1;
                    if(check(mid<<1)-check(mid)<=m)
                        R=mid,l=mid+1;
                    else r=mid-1;
                }
                printf("%lld %lld
    ",L,R-L+1);
            }
        }
    }
    
  • 相关阅读:
    Ribbon【负载均衡策略】
    Ribbon【入门】
    Mysql主从复制原理及同步延迟问题
    JWT 身份认证优缺点分析以及常见问题解决方案
    Feign【token传递】
    Feign【首次请求失败】
    Feign【文件上传】
    Feign【替换默认的feign client】
    Feign【开启GIZP压缩】
    Feign【@FeignClient】
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/15484249.html
Copyright © 2011-2022 走看看