C. Manhattan Permutations

曼哈顿排列的值是 i=1n|pii|, p 是排列。

给定曼哈顿排列值,要求构造出这个排列。

Solution

每次都能想到正确思路,但是就是写不出来,总感觉差点什么...

构造

首先讨论不可能的情况:

最大的数据是:1,2,3,nn,n1,1 这个两个排列的差的情况。

i=1n|n2×i+1|=i=1n+12(n2×i+1)+i=n+12+1n(2×in1)

拆开化简后最大值即为 $$2\times\lfloor{\frac{n+1}{2}}\rfloor(n-\lfloor{\frac{n+1}{2}}\rfloor)$$
再讨论符合条件的情况如何构造:

1n 交换时,可以构造 2(n1) 的值,2n1 交换可以构造 2(n3) 这样的值,...,一共可以构造:

i=1n2(n+12×i)=MAX 的值。所以这个情况是一定能够构造出所有可能的。

k<2(n1) 时:1 就不和 n 交换,和 n1,n2 其中一个交换,
能构造的值 v=2(n3)4k(k=0,1,2)v0

k2(n1) 时:1n 交换,进行下一轮,能构造的值为 2(n1)

后面的同理,容易知道能够构造所有合理值。

Example

例如:
n=5,k=6,若 1 和 5 交换可以构造 2(n1)=8>6,所以 1 和 n1=4 交换 (1,4)(4,1) 得到 6.

n=5,k=10,若 1 和 5 交换可以构造 2(n1)=8<10,所以 1 和 5 需要交换,剩下 2。
下一轮若 2 和 4 交换可以构造 2(n3)=4>2,所以不交换,选择之前的值 n2,n3,可以知道 2 和 3 交换后恰好构造出 2,得到 2。

#define int long long
void solve() {
    int n, k;cin >> n >> k;
    int m = (n + 1) / 2;
    int p = 2 * m * (n - m);
    if (k & 1 || k > p) {
        cout << "NO\n";return;
    }
    cout << "YES\n";
    vector<int> a(n + 1);
    for (int i = 1;i <= n;i++)a[i] = i;
    k /= 2;
    for (int i = 1;k > 0;i++) {
        if (k < n - 2 * i + 1) {
            swap(a[i], a[i + k]);k = 0;
        } else {
            swap(a[i], a[n - i + 1]);
            k -= n - 2 * i + 1;
        }
    }
    for (int i = 1;i <= n;i++)cout << a[i] << " \n"[i == n];
}