P1338 末日的傳說

題目描述:

只要是參加jsoi活動的同學一定都聽說過Hanoi塔的傳說:三根柱子上的金片每天被移動一次,當所有的金片都被移完之後,世界末日也就隨之降臨了。

在古老東方的幻想鄉,人們都採用一種奇特的方式記錄日期:他們用一些特殊的符號來表示從1開始的連續整數,1表示最小而N表示最大。創世紀的第一天,日曆就被賦予了生命,它自動地開始計數,就像排列不斷地增加。

我們用1-N來表示日曆的元素,第一天日曆就是

1, 2, 3, … N

第二天,日曆自動變爲

1, 2, 3, … N, N-1

……每次它都生成一個以前未出現過的“最小”的排列——把它轉爲N+1進制後數的數值最小。

日子一天一天地過着。有一天,一位預言者出現了——他預言道,當這個日曆到達某個上帝安排的時刻,這個世界就會崩潰……他還預言到,假如某一個日期的逆序達到一個值M的時候,世界末日就要降臨。

什麼是逆序?日曆中的兩個不同符號,假如排在前面的那個比排在後面的那個更大,就是一個逆序,一個日期的逆序總數達到M後,末日就要降臨,人們都期待一個賢者,能夠預見那一天,到底將在什麼時候到來?

輸入輸出格式

輸入格式:

只包含一行兩個正整數,分別爲N和M。

輸出格式:

輸出一行,爲世界末日的日期,每個數字之間用一個空格隔開。

 

輸入輸出樣例

輸入樣例#1:

5 4

輸出樣例#1:

1 3 5 4 2

 

題目意思看了半天沒看懂搜了題解看到的題意。意思是給你一個N,讓你在1-N的序列中找到一個序列使得這個序列的逆序對的個數滿足M,並且該序列的字典序最小。

對於一個序列,它的最大逆序對的個數給n*(n-1)/2,即該序列嚴格降序。所以當我們按位來考慮這個序列的逆序數時,我們去判斷這一位對該序列逆序對的貢獻是否比M大。例如N = 5,M = 4.我們在考慮1的時候可以計算得出,剩下的4位數可以產生的最大逆序對的個數是比M大的,所以這個1可有可無,我們就可以把他放到序列的最前端。而到了2時我們發現,去掉了這個2是無法滿足逆序對大於M的要求,此時按照貪心我們把2放到最後,這樣可以使2這個數產生的逆序對最多,也就使M減小的最多,進而影響後面我們可以找到跟多的無關元素。這樣就好寫了。對於每個數都有兩種方式 

  1. 去掉當前數,剩下的數仍可構成比M多個逆序對
  2. 把當前數放到後方,讓M-(當前數提供的逆序對的個數)

這樣直接O(n)的時間複雜度就過去了(要開long long)。

#include <bits/stdc++.h>
typedef long long ll;
const int MAXN = 1e5+7;
const int INF = 0x7fffffff;
using namespace std;
ll a[MAXN];

int main() {
    ll n,m;
    cin >> n >> m;
    ll ans[MAXN],l = 1,r = n;
    for(ll i = 1; i <= n; i++) {
        ll t = (n-i)*(n-i-1)/2;
        if(t >= m) {
            ans[l] = i;
            l++;
        } else {
            ans[r] = i;
            r--;
            m -= (r - l + 1);
        }
    }
    for(ll i = 1; i <= n; i++)
        cout << ans[i] << " ";
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章