Envious Exponents 二进制

4897: Envious Exponents

时间限制: 1 Sec  内存限制: 128 MB
提交: 306  解决: 49
[提交] [状态] [讨论版] [命题人:admin]

题目描述

Alice and Bob have an integer N. Alice and Bob are not happy with their integer. Last night they went to a cocktail party and found that another couple had the exact same integer! Because of that they are getting a new integer.

Bob wants to impress the other couple and therefore he thinks their new integer should be strictly larger than N.
Alice herself is actually fond of some specific integer k. Therefore, Alice thinks that whatever integer they pick, it should be possible to write it as a sum of k distinct powers of 2.

Bob is also a cheapskate, therefore he wants to spend as little money as possible. Since the cost of an integer is proportional to its size, he wants to get an integer that is as small as possible.

 

输入

• A single line containing two integers N and k, with 1 ≤ N ≤ 1018 and 1 ≤ k ≤ 60.

 

输出

Output M, the smallest integer larger than N that can be written as the sum of exactly k distinct powers of 2.

 

样例输入

1 2

 

样例输出

3

 

来源/分类

BAPC2017 Preliminaries 

 

[提交] [状态]

这题,调代码调到彻底自闭,然后更自闭的事情是,是函数用错了,其他地方都没bug

题意:给数n和k,求使一个最小的大于n的数m,使m = 2^{a} + 2^{b} + \cdots \cdots(k个2的幂次数相加,且幂次各不相同)

这个题如果找对方向,就很快能写出来,但是没有的话,就很难办了(显然我们的方向找的太慢了)

用二进制的思想,将n二进制中的1和k比较,进行加1或减1的操作,就好了

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=100;
typedef  long long ll;
int a[maxn];

int main(){
    ll n,k;
    scanf("%lld%lld",&n,&k);
    ll nn = n;
    int z = 0;
    int q=0;
    while(nn != 0){
        a[z++] = nn % 2;
        if(nn%2==1) q++;
        nn /= 2;
    }
    if(q < k){
        for(int i=0; ; i++){
            if(q == k)  break;
            if(a[i]==0){
                a[i]=1;
                q++;
                if(i>=z){
                    z++;
                }
            }
        }
    }
    else{
        int v = q - k;
        for(int i=0; i<z && v>0; i++){
            if(a[i]==1){
                a[i]=0;
                v--;
            }
        }
        int p = -1;
        for(int i=0; i<z; i++){
            if(a[i]==1 && a[i+1]==0){
                p = i+1;
                break;
            }
        }
        if(p==z){
            memset(a,0,sizeof(a));
            a[z++]=1;
            int t = k-1;
            for(int i=0; i<z && t>0; i++){
                a[i]=1;
                t--;
            }
        }
        else{
            a[p]=1;
            q = k+1;
            for(int i=0; i<p; i++){
                if(a[i]==1){
                    a[i]=0;
                    q--;
                }
            }
            int ss = k - q;
            for(int i=0; i<p && ss>0; i++){
                a[i]=1;
                ss--;
            }
        }
    }
    ll ans = 0;
    for(int i=0; i<z; i++){
        if(a[i]==1)
            ans += (1ll << i);
    }
    printf("%lld\n",ans);
    return 0;
}

左边的大佬计算了数据,发现最大位数不会超过60,于是数组的边界就不用维护了,减少了很多麻烦(可能出现的bug)

还有把十进制转换为二进制的写法

我得改改了

for(int i=0; i<61; i++){
    if(n & (1ll << i))
        a[i] = 1;
    else 
        a[i] = 0;
}

还有右边大佬的代码,用了一个bitset ,直接存二进制的STL工具

直接上代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int k;
unsigned long long a;
bitset<64> ans;
int main()
{
    cin>>a>>k;
    ans=a;
    if(ans.count()<k)
    {
        k-=ans.count();
        while(k--) a=a|(a+1);
        cout<<a<<endl;
    }
    else
    {
        int cou=ans.count()-k,j=0;
        bool flag=0;
        for(int i=0; i<64; i++)
        {
            if(ans[i])
            {
                if(!cou && !flag) flag=1;
                else if( flag) ans.set(j++);
                else if(!flag) cou--;
                ans.reset(i);
            }
            else if(flag)
            {
                ans.set(i);
                break;
            }
        }
        cout<<ans.to_ulong()<<endl;
    }
    return 0;
}

最后,说说出错的那个函数__builtin_popcount

用来计算一个数二进制位下有多少个1

听起来是没有错,可是

以后还是多了解了解再用。

posted @ 2018-08-25 10:39  任小喵  阅读(137)  评论(0编辑  收藏  举报