只要是參加jsoi活動的同學一定都聽說過hanoi塔的傳說:三根柱子上的金片每天被移動一次,當所有的金片都被移完之後,世界末日也就隨之降臨了。
在古老東方的幻想鄉,人們都採用一種奇特的方式記錄日期:他們用一些特殊的符號來表示從1開始的連續整數,1表示最小而n表示最大。創世紀的第一天,日曆就被賦予了生命,它自動地開始計數,就像排列不斷地增加。
我們用1-n來表示日曆的元素,第一天日曆就是
1, 2, 3, … n
第二天,日曆自動變為
1, 2, 3, … n, n-1
……每次它都生成乙個以前未出現過的「最小」的排列——把它轉為n+1進製後數的數值最小。
日子一天一天地過著。有一天,一位預言者出現了——他預言道,當這個日曆到達某個上帝安排的時刻,這個世界就會崩潰……他還預言到,假如某乙個日期的逆序達到乙個值m的時候,世界末日就要降臨。
什麼是逆序?日曆中的兩個不同符號,假如排在前面的那個比排在後面的那個更大,就是乙個逆序,乙個日期的逆序總數達到m後,末日就要降臨,人們都期待乙個賢者,能夠預見那一天,到底將在什麼時候到來?
發現窩模擬有大問題,這道題就是個簡單的貪心,結果窩思路清晰依然寫不出。。。
題目要求我們輸出乙個長度為\(n\)的含有\(m\)個逆序對的字典序最小的序列。
眾所周知,乙個長度為\(n\)的序列最多貢獻\(n(n-1)/2\)個逆序對,因此當我們把某個數\(i\)放到序列末尾時,除了之前在這個數後面的數會與它形成逆序對之外,還會最多產生\((n-i)(n-i-1)/2\)個逆序對。我們只需貪心地每次選擇最靠後的能使產生的逆序對小於\(m\)個數放到序列末尾,就可以產生乙個符合要求的序列。
一開始本來想寫遞迴的,發現我太蒻,竟然不會寫。。。(太菜了
#include#include#include#include#include#include#include#include#include#include#define ll long long
#define n 50010
using namespace std;
ll n,m,ans[n];
int main()
for(int i=1;i<=n;++i) printf("%lld ",ans[i]);
return 0;
}
P1338 末日的傳說
首先審題,題目中提到 每次它都生成乙個以前未出現過的 最小 的排列。其實這句話的意思就是說,我這個日期每天都會變化,每次變化後的排列都是以前沒出現過的,也就是不會有重複的排列,然後這個日期還是除了以前出現過的排列之外的最小的排列,也就是說啊,我這個日期是按照一定規律來變化的,第一天是字典序最小,第二...
洛谷P1338(末日的傳說)
只要是參加jsoi活動的同學一定都聽說過hanoi塔的傳說 三根柱子上的金片每天被移動一次,當所有的金片都被移完之後,世界末日也就隨之降臨了。在古老東方的幻想鄉,人們都採用一種奇特的方式記錄日期 他們用一些特殊的符號來表示從1開始的連續整數,1表示最小而n表示最大。創世紀的第一天,日曆就被賦予了生命...
洛谷P1338 末日的傳說
qaq本來不是多難的題,然鵝我折騰了半天。看到乙個挺不錯的想法 我們知道,對於乙個長度為n的序列而言,其最大的逆序對的個數為n n 1 2,題目是要求乙個逆序數為m的字典序最小的序列。那我們不妨從1開始考慮每乙個數的排列,這樣每次考慮的都是當前最小的數 如果把這個數放在最前面,而剩下的數的排列的逆序...