只要是參加jsoi活動的同學一定都聽說過hanoi塔的傳說:三根柱子上的金片每天被移動一次,當所有的金片都被移完之後,世界末日也就隨之降臨了。
在古老東方的幻想鄉,人們都採用一種奇特的方式記錄日期:他們用一些特殊的符號來表示從1開始的連續整數,1表示最小而n表示最大。創世紀的第一天,日曆就被賦予了生命,它自動地開始計數,就像排列不斷地增加。
我們用1-n來表示日曆的元素,第一天日曆就是
1, 2, 3, … n
第二天,日曆自動變為
1, 2, 3, … n, n-1
……每次它都生成乙個以前未出現過的「最小」的排列——把它轉為n+1進製後數的數值最小。
日子一天一天地過著。有一天,一位預言者出現了——他預言道,當這個日曆到達某個上帝安排的時刻,這個世界就會崩潰……他還預言到,假如某乙個日期的逆序達到乙個值m的時候,世界末日就要降臨。
什麼是逆序?日曆中的兩個不同符號,假如排在前面的那個比排在後面的那個更大,就是乙個逆序,乙個日期的逆序總數達到m後,末日就要降臨,人們都期待乙個賢者,能夠預見那一天,到底將在什麼時候到來?
輸入格式:
只包含一行兩個正整數,分別為n和m。
輸出格式:
輸出一行,為世界末日的日期,每個數字之間用乙個空格隔開。
我們考慮把這個問題縮小範圍。
比如n=5,在決定了最小的數「1」的位置之後,剩下的幾個數是2 3 4 5,但是他們
具體是多少沒必要關心,我們只要關心他們的相對大小關係。
所以考慮完當前最小的數,算出這個數對答案的貢獻,然後減掉這個貢獻,
就可以轉而解決乙個更小的子問題。(即n-->n-1)
回到題目上,要求是求乙個有m個逆序對的字典序最小的排列。
我們知道乙個長度為n的排列最多有(n-1)*n/2個逆序對,也知道乙個排列的逆序對數越多,排列字典序越大。
所以如果當前m不比當前的(n-2)*(n-1)/2(也就是減少乙個數之後的最多的逆序對數)大,
就可以直接把當前的最小數放在最前面,這肯定是最優的。
反之,則考慮最小數的放置位置。
假設當前排列長為n,最小數為a,則a有n種放法,放在從左到右第i個位置時會生成i-1個逆序對
(因為它左邊有i-1個比他大)。
因為m大於n-1長度排列最多所能產生的逆序數,所以a不可能放在最前面,否則不滿足條件。
怎麼辦呢?想到之前說的逆序對越多字典序越大,我們就必須讓剩下的數能構成的逆序對數盡量小,所以a要放到最後,這樣m減少的最多。
放完了a,問題就變成了n-1和m-(a的貢獻)的子問題,遞迴求解即可。時間複雜度o(n)。
#includetypedef long long ll;
ll n,m,a[50005];
int main()
for(int i=1;i<=n;i++)printf("%lld ",a[i]);
return 0;
}
洛谷P1338 末日的傳說
qaq本來不是多難的題,然鵝我折騰了半天。看到乙個挺不錯的想法 我們知道,對於乙個長度為n的序列而言,其最大的逆序對的個數為n n 1 2,題目是要求乙個逆序數為m的字典序最小的序列。那我們不妨從1開始考慮每乙個數的排列,這樣每次考慮的都是當前最小的數 如果把這個數放在最前面,而剩下的數的排列的逆序...
洛谷P1338 末日的傳說
只要是參加jsoi活動的同學一定都聽說過hanoi塔的傳說 三根柱子上的金片每天被移動一次,當所有的金片都被移完之後,世界末日也就隨之降臨了。在古老東方的幻想鄉,人們都採用一種奇特的方式記錄日期 他們用一些特殊的符號來表示從1開始的連續整數,1表示最小而n表示最大。創世紀的第一天,日曆就被賦予了生命...
洛谷 P1338 末日的傳說
大概題意 就是求 1 1 到n n 的排列中字典序最小的乙個滿足逆序對個數為m m的排列。1 n m 分析 首先我們要知道乙個排列能有的最多逆序對 n n 1 2 即當他為嚴格遞增序列時 而我們又知道逆序對越多該數列的字典序越大 因此可對題意這樣分析,很明顯從最小的數 i 開始考慮 如果除去該數 剩...