• 【codeforces 431D】Random Task


    【题目链接】:http://codeforces.com/problemset/problem/431/D

    【题意】

    给你一个数字m和数字k;
    让你找一个数字x;
    使得x+1..2*x这个区间范围内的数,它们的二进制形式里面,1的个数恰好为k个的数字恰好有m个;

    【题解】

    首先需要知道x+1..2*x这里面二进制1的个数的为k的数字的个数是随着x单调不下降的;
    比如

    n = x=>x+1,x+2...2*x
    n = x+1=>  x+2...2*x,2*x+1,2*x+2


    这里x+1的1的个数和2*x+2的1的个数是一样的;
    因为乘2的话,会让所有的1整体左移;但1的个数不变;
    这样
    x+1,x+2…2*x
    x+2…2*x,2*x+2
    它们俩含k个1的个数是相同的;
    但是n=x+1的时候还有一个2*x+1;这个数字可能是含k个1的,所以说是单调不下降的;
    知道单调性之后;
    就二分n吧.
    然后求某个范围(L,R]里面二进制有k个的1的数的个数;
    可以先求出1..L和1..R这两个区间范围内的有k个1的数的个数;
    然后相减就是这个区间的了;
    而求1..x中有k个1的数的个数;
    是个计数的问题了;
    具体的,把x的二进制形式中的某个1给变成0;
    (计数完之后还原就是了);
    然后假设这是从右往左数第i位;
    则在i-1个数字中选择剩下的所需的1的个数就好(k减去这一位左边的1的个数);
    (因为第i位是1,所以变成0后,后面可以出现任意数量的1);
    如果x也是k个1别忘了算上;

    【Number Of WA

    0

    【完整代码】

    #include <bits/stdc++.h>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define LL long long
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define ms(x,y) memset(x,y,sizeof x)
    #define Open() freopen("F:\rush.txt","r",stdin)
    #define Close() ios::sync_with_stdio(0),cin.tie(0)
    
    typedef pair<int,int> pii;
    typedef pair<LL,LL> pll;
    
    const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};
    const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};
    const double pi = acos(-1.0);
    const int N = 66;
    
    LL m,k;
    LL c[N][N],t[N];
    
    void pre(){
        t[0] = 1;
        rep1(i,1,63){
            t[i] = t[i-1]*2;
        }
        rep1(i,0,65)
            c[i][0] = c[i][i] = 1;
        rep1(i,1,65){
            rep1(j,1,i-1){
                c[i][j] = c[i-1][j]+c[i-1][j-1];
            }
        }
    }
    
    LL get_sum(LL x){
        int cur = 0;
        LL temp = 0;
        for (LL i = 63;i >= 0;i--)
        if (x&t[i]){
            if (k-cur>=0)
                temp += c[i][k-cur];
            cur++;
        }
        if (cur==k) temp++;
        return temp;
    }
    
    LL check(LL n){
        LL temp1 = get_sum(2*n);
        LL temp2 = get_sum(n);
        temp1-=temp2;
        return temp1;
    }
    
    int main(){
        //Open();
        Close();//scanf,puts,printf not use
        //init??????
        pre();
        cin >> m >> k;
        LL l = 1,r = (LL) 1e18,ans = 0;
        while (l <= r){
            LL mid = (l+r)>>1;
            LL temp = check(mid);
            if (temp>=m){
                ans = mid;
                r = mid - 1;
            }else {
                l = mid + 1;
            }
        }
        cout << ans << endl;
        return 0;
    }
  • 相关阅读:
    转载【Ubuntu】Ubuntu14.04虚拟机调整窗口大小自适应VMware14窗口
    【ubuntu】安装输入法
    【虚拟机ubuntu】安装之后安装VMware tools
    【虚拟机ubuntu设置ssh】ssh连不上问题解决方法
    JavaScript常用函数
    Label自适应高度
    xcode 删除文件后编译会出现*** is missing from working copy
    找window的三种方法
    怎么查看Mac电脑的开机记录?
    iOS 跳转到系统的设置界面
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626272.html
Copyright © 2020-2023  润新知