p-binary

p-binary

p-binary 题目链接

错误思路

先说一下我一开始样例都过不了的思路把,由于 (n <= 1e9, 1000 <= p <= 1000),所以我们可以先写至多前50项的 (2 ^ i - p),然后通过不断地减去与其最接近的值,最后得到最优答案。

正确思路

我们先列出式子来

(n = 2 ^ {k_1} + p + 2 ^ {k_2} + p …… 2 ^ {k_(m-1)} + p + 2 ^ {k_m} + p 其中 k_i in{[0,+infty]} 且 k_i in{Z})

我们不妨对式子变形得到的是

(n - pm = 2 ^ {k_1} + 2 ^ {k_2} + 2 ^ {k_3} …… 2 ^{k_(m-1)} + 2 ^ {k_m})

由于 (2 ^ {k_i}) 是一定大于零的,(n <= 1e9),如果这个时候 (p) 是取 (-1),也就是极限条件了,这里就需要最多加 (1e9) 次,所以我们简单的暴力枚举 (1e9) 次,其实并不用枚举这么多次,(long long) 范围内最多也就是 (2 ^ {64} - 1),当我们暴力次数增加到最多几百次的时候就可以锁定答案到底存在不存在了

接下来的工作就是判断 (m) 是否等于当前可拆分的 (2 ^ k) 的倍数也就是

  • 判断 (n - pm) 中二进制数有多少个 (1),同时要注意一个 (4) 可以拆分成_两个二_,一个二两个一四个一,也就是其可组成的 (2 ^ k) 就是 (n - pm) 个。
  • 然后就是要判断是否可以组成m个 (2 ^ k),也就是 (m <= p <= n - pm)

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 55;
ll a[N], n, p;
inline ll lowbit(ll x) {
    return (-x) & (x);
}
int main() {
    // freopen("in.txt", "r", stdin);
    // while(cin >> n >> p) {
        cin >> n >> p;
        int flag = 0;
        for(int i = 1; i <= 1000; i++) {
            ll t = n - i * p;
            if(t <= 0) {
                break;
            }
            int sum = 0, num = 0;
            while(t) {
                ll temp = lowbit(t);
                t -= temp;
                num += temp;
                sum++;
            }
            if(num >= i && sum <= i) {//num其实最后就是t
                flag = i;
                break;
            }
        }
        if(flag)   cout << flag << "
";
        else    puts("-1");
    // }
    return 0;
}
原文地址:https://www.cnblogs.com/lifehappiness/p/12802677.html