题解 | 牛牛的构造

牛牛的构造

https://www.nowcoder.com/practice/eb9e250a57a74942b107f85120b7c301

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
using vi = vector<int>;
int f(int cnt) {
    int sum = 0;
    cnt--;
    while (cnt) {
        sum++;
        cnt/=2;
    }
    return sum;
}

void solve() {
    int n, k;cin >> n >> k;
    int t = 1;
    int sum = 0;
    while (t <= n) {
        sum += n - t;
        t *= 2;
    }
    if (sum < k) {
        cout << -1 << endl;return;
    }
    vi st(n + 1);
    int cnt = n;
    sum = 0;
    while (cnt > 0) {
        while (1) {
            if (sum + f(cnt) <= k) {
                break;
            }
            cnt--;
        }
        int tt = f(cnt);
        st[cnt] = 1;
        cout << cnt << " ";
        sum += f(cnt);
        cnt--;
    }
    for (int i = 1;i <= n;i++) {
        if (st[i] == 0)cout << i << " ";
    }
}


/*

*/


signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int t = 1;
    //cin >> t;
    for (int i = 1; i <= t; i++) {
        //cout << "----Test " << i << "----" << endl;
        solve();
    }
    return 0;
}

先考虑大于多少数是无解的,那肯定是从大到小的排列是最多的,考虑每个数字的贡献,1贡献0,2贡献1,3贡献2,4贡献2,5贡献3,因为5可以跟1 3 4配对,刚好差值是4 2 1,得出跟二进制有关系,得到计算贡献函数

int f(int cnt) {
    int sum = 0;
    cnt--;
    while (cnt) {
        sum++;
        cnt/=2;
    }
    return sum;
}

然后从大到小,根据贡献从前往后填数字,当前值总贡献值+当前数贡献>k的时候,就cnt--换更小的数,如果是<=就直接输出这个数,然后标记这个数访问过。最后从小到大输出未访问的数字,这些数字不会影响最后的贡献

全部评论

相关推荐

01-19 12:48
门头沟学院 C++
只想搞钱的鸽子很喜欢...:混账是很多的,还有那些在自己风华正茂的年纪说风凉话讥讽那些下岗前员工的。这些人都是现在职场环境这么烂的帮凶
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务