【ZOJ 2425】 Inversion

Description

給定N的值,要求找出一個N的全排列,這個全排列中,逆序數有M對。這樣的結果會存在多個解,現在請輸出字典序最小的那個解。例如當輸入3 1 時,則1 3 2這個排列有一個逆序對,2 1 3這個排列同樣也有一個逆序對。但1 3 2這個字典序更小,因而其是正解。

Input

每組數據給出N,M。1 <= n <= 50000 and 0 <= m <= 1/2*n*(n-1).
整個測試以-1 -1代表結束。

Output

如題

Sample Input

5 9
7 3
-1 -1

Sample Output

4 5 3 2 1
1 2 3 4 7 6 5

HINT

Source



不難得出一個結論,長度爲N的序列中,逆序對最多有(N*(N-1)/2)對,要求字典序最小,自然就想到貪心,從最後開始加,如果已有的N個數的最多逆序對數(N*(N-1)/2)小於要求的個數,將沒加進來的數中最大的那個填到答案中,再計算和判斷,進行到最後,將出現兩種情況:

①如果最大逆序數和要求的剛好相等,直接從大到小填入即可
最大逆序數比要求的要小M,將之前最後填入的那個數和向後移M位即可

比如 123498765 序列的逆序數比要求的小3
只需要把4向後移動3位 變成123987465

#include<cstdio>
using namespace std;
 
const int MAX_LEN = 50000;
int ans[MAX_LEN];
void print_ans(int n, int m) {
    int i = 2;
    while (i <= n && i * (i - 1) / 2 <= m)
        i++;
    i--;
    int k = n + 1 - i;
    int lt = m - i * (i - 1) / 2;
 
    int pos = 0;
    for (int w = 1; w < k - 1; w++, pos++)
        ans[pos] = w;
    ans[pos++] = k - 1 + lt;
    for (int w = n; w >= k - 1; w--) {
        if (w != (k - 1 + lt))
            ans[pos++] = w;
    }
 
    printf("%d", ans[0]);
    for (int w = 1; w < n; w++)
        printf(" %d", ans[w]);
}
int main() {
    int n, m;
    while (true) {
        scanf("%d %d", &n, &m);
        if (n == -1 && m == -1)
            break;
        print_ans(n, m);
        printf("\n");
    }
    return 0;
}
 
/**************************************************************
    Problem: 1130
    User: xrq
    Language: C++
    Result: Accepted
    Time:16 ms
    Memory:1148 kb
****************************************************************/




發佈了88 篇原創文章 · 獲贊 6 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章