题意:给你一个n和一个p,让你用 (2k+p)进制来表示n,找出用最少的(2k+p)来表示n。
分析:首先我们看到2k,首先下想到二进制,我们可以我们列出式子,也就是
(2x1 + p)+(2x2 + p)+(2x3 + p)+……+(2xk + p) == n
然后我们转换为 2x1 +2x2 +2x3 +……+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; }