cf1509E - Almost Sorted

cf1509E - Almost Sorted

传送门

题意: 定义almost sorted的排列是 a i + 1 ≥ a i − 1 a_{i+1} \geq a_i - 1 ai+1ai1,给出排列长度n,问字典序第k大的排列

可以发现长度为n的满足的排列只有 2 n − 1 2^{n - 1} 2n1个,注意直接位移会溢出,(n1e5)

自己刚开始在想从长度为n到长度为n+1的转移,前一半是每个数+1然后在开头放1,(没有什么头绪

题解感觉很妙很妙,

将n分块,每一段表示长度为 n u m i num_i numi 的顺序递减序列,这与要求的almost sorted排列一一对应,于是可以将问题转化过来

用0表示每个段的末尾,1表示剩下的,(最后一位必是0于是我们先不管)这样可以很愉快地得到一个二进制,他刚好就是k-1的二进制表示(二进制从0000开始,则第k个就是k-1的二进制

题解给了一张示意图(高度表示数
x轴01是刚才的二进制,

在这里插入图片描述

#include <bits/stdc++.h>

using namespace std;

typedef unsigned long long ll;

ll n, k;

string getBin(ll x) {
    string s = "";

    for (int i = 0; i < n; i++)
        s += '0';
    k--;
    for (ll b = 0; b < min((ll) 60, (ll) (n - 1)); b++) {
        if ((k >> b) & 1)
            s[n - 2 - b] = '1';
    }
    return s;
}

vector<int> vec;

int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T;
    cin >> T;
    while (T--) {
        vec.clear();
        cin >> n >> k;
        if (n <= 62 && k > (1ll << (n - 1))) {
            cout << -1 << endl;
            continue;
        }
        string tmp = getBin(k);

        int len = tmp.size();
        int cnt = 0;
        for (int i = 0; i < len; ++i) {
            if (tmp[i] == '0') {
                vec.push_back(cnt + 1);
                cnt = 0;
            } else {
                cnt++;
            }
        }
        if (cnt) {
            vec.push_back(cnt);
        }
        int nw = 0, pre = 0;
        for (auto x: vec) {
            pre = nw;
            nw = nw + x;
            for (int i = nw; i > pre; --i) {
                cout << i << " ";
            }
        }

        cout << endl;
    }
    return 0;
}
  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值