codeforces 596 C. p-binary

题意:给你一个n和一个p,让你用 (2k+p)进制来表示n,找出用最少的(2k+p)来表示n。

分析:首先我们看到2k,首先下想到二进制,我们可以我们列出式子,也就是

   (2x1 + p)+(2x+ p)+(2x+ p)+……+(2x+ p) == n

  

   然后我们转换为  2x+2x+2x+……+2xk  == n- m*p

   这样问题就转换为求 m的最小值是多少。

   我们再分析,由于数据给出 n < 109  ,所以 m < 32。

   这样我们就可以从小到大暴力枚举m的大小。

   最后判定条件为  (n-m*p)的二进制中1的个数 <=m && m<=n-m*p  ,则 m 就是答案。

   先解释下第一个判定条件  由于二进制中 ,高位的 1 可以分解为 两个低1位的  1 ,所以如果  (n-m*p)的二进制中1的个数 < m ,那么 (n-m*p)中的二进制中高位的1就可以不断分解直到 等于 m

   再解释下第二个判定条件 由于二进制中,最低为就是 20,也就是十进制的 1 ,所以 (n-m*p)的二进制 最多分解为 (n-m*p)个  20,所以 m<=n-m*p。

  

//#pragma comment(linker, "/STACK:1024000000,1024000000")
//#pragma GCC optimize(2)
#include <bits/stdc++.h>

using namespace std;
typedef double dou;
typedef long long ll;
typedef pair<int, int> pii;
typedef map<int, int> mii;

#define pai acos(-1.0)
#define M 1000005
#define inf 0x3f3f3f3f
#define mod 1000000007
#define IN inline
#define W(a) while(a)
#define lowbit(a) a&(-a)
#define left k<<1
#define right k<<1|1
#define lson L, mid, left
#define rson mid + 1, R, right
#define ms(a,b) memset(a,b,sizeof(a))
#define Abs(a) (a ^ (a >> 31)) - (a >> 31)
#define random(a,b) (rand()%(b+1-a)+a)
#define false_stdio ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)

int n, p;

int main() {
    false_stdio;
    cin >> n >> p;
    for (int i = 0; i < 32; i++) {
        int tmp = n - i * p;
        if(__builtin_popcount(tmp)<=i && i<=tmp){ // __builtin_popcount 是gcc中的内置函数,用于计算二进制中1的个数 
            cout<<i<<endl;    
            return 0;
        }
    }
    cout<<-1<<endl;

    return 0;
}

   

原文地址:https://www.cnblogs.com/caibingxu/p/11779499.html