Skip to content

CF2040C Ordered Permutations

原题链接:C. Ordered Permutations

Tag:注意力

题目描述

给定一个长度为 \(n\) 的整数排列 \(p_1, p_2, \ldots, p_n\),其中包含从 \(1\)\(n\) 的所有整数。我们定义一个如下的和式:

\[S(p) = \sum_{1 \le l \le r \le n} \min(p_l, p_{l+1}, \ldots, p_r)\]

我们希望找出所有能使 \(S(p)\) 最大的排列,并从中按字典序选择第 \(k\) 个。如果这样的排列数量少于 \(k\),则输出 -1。

数据说明:

\(1 \le n \le 2 \cdot 10^5\); \(1 \le k \le 10^{12}\)

分析

首先考虑一下 \(S\) 的最大值, 可以发现我们把 \(1\)\(n\) 的所有数字按顺序排列时可以得到最大值。

思考一种情况,如果我们已经从大到小构造好了一部分,那么下一个小 \(1\) 的数字应该放在那里。 如果我们把下一个数字放在中间,那么很显然,之前排列好的部分中有很多区间贡献会被减少, 所以我们应该把下一个数字放在前面或者后边。 因此我们对 \(k\) 进行二进制拆分决定放在前面还是后面即可。

代码实现

void NeverSayNever() {
    int n,k;
    cin >> n >> k;
    k--;
    deque<int> dq;
    dq.push_back(n);
    int cur = n - 1;
    while (k) {
        if (k & 1) dq.push_back(cur);
        else dq.push_front(cur);
        cur--;
        k >>= 1;
    }
    if (cur < 0) {
        cout << -1 << endl;
        return;
    }
    for (int i = cur; i > 0 ; i--) {
        dq.push_front(i);
    }
    for (auto &x: dq) {
        cout << x << ' ';
    }
    cout << endl;
}

日志

本页面创建于 2024/02/16 14:59