給乙個長度為\(n\)的排列\(p\)與乙個正整數\(k\),可以進行如下操作:
對於兩個滿足\(|i-j|\geq k\) 且\(|p_i-p_j|=1\)的下標\(i\)和\(j\),交換\(p_i\)與\(p_j\)
我們的目的是要求操作後的排列字典序最小
首先,這兩個條件都不好判斷,直接做是不太好搞的
考慮把這個陣列對映一下(這好像是對於排列的乙個常見套路?)
令\(pos[p_i]=i\),即元素\(p_i\)的位置為\(i\)
我們對\(pos\)陣列進行操作,操作就轉化為了:
可以交換兩個相鄰元素,並且相鄰元素的差的絕對值\(\geq k\)
我們發現,對於兩個元素\(i,j,i,如果\(|i-j|,那麼它們的相對位置永遠不會改變
也就是說無論進行多少次交換,如何交換,\(i\)一定會在\(j\)之前
這就啟發我們用拓撲排序進行求解
但是我們應按照一種什麼樣的規則選擇求出的拓撲序,使得原排列的字典序最小呢?
網上有許多題解都認為,原序列的字典序最小等價於求逆序列的字典序最小
但實際上這個想法是錯誤的,可以舉一組反例來說明
我們可以發現,第乙個排列的字典序比第二個大,但其逆序列的字典序卻比第二個小實際上,真正正確的結論是原序列的字典序最小,等價於其逆序列的反序列的字典序最大
那麼接下來的任務就是建圖了
為了避免重複連邊,我們規定乙個元素僅能向其後面的元素連邊
考慮連邊的意義,若存在一條有向邊\(e(u,v)\),說明\(u,v\)之間的相對順序已經確定即\(v\)在\(u\)之後
對於乙個元素\(x\),它會向值域為\((x-k,x)\cup (x,x+k)\)的元素連邊,並且要求這些元素的初始位置在\(x\)之後
但是這樣暴力連邊,邊的數量是\(o(n^2)\)級別的
我們可以發現,相對順序是有傳遞關係的,比如說對於三條邊\(a \rightarrow b, b\rightarrow c,a\rightarrow c\),第三條邊完全可以被前兩條邊替代,那麼它就是無效的
為了去掉這些無效的邊,我們規定\(x\)只向值域為\((x-k,x)\)與\((x,x+k)\)中的位置在\(x\)之後且最小的元素連邊
這是因為我們可以發現由於這兩個集合的大小均不超過\(k\),那麼它們內部一定是互有連邊的
那麼我們只需要連乙個位置最靠前的元素,就可以根據這個元素擴張到整個集合了
由於是求逆序列的反序列最大,我們需要建反圖,並用大根堆求字典序最大的序列
找到這個元素可以用線段樹實現,由於合法的元素一定在當前元素之後,所以倒序加點即可
#include #include #include #include using namespace std;
const int n = 5e5 + 10;
int read();
int n, k;
int p[n], q[n];
int cap;
int head[n], deg[n], to[n << 1], nxt[n << 1];
priority_queueque;
inline int min(int x, int y)
inline int max(int x, int y)
struct segtree
void change(int x, int l, int r, int k, int v)
int query(int x, int l, int r, int ls, int rs)
} tr;
inline void add(int x, int y)
int main()
for (int i = 1; i <= n; ++i)
if (!deg[i]) que.push(i);
for (int i = n; i >= 1; --i)
for (int i = 1; i <= n; ++i) q[p[i]] = i;
for (int i = 1; i <= n; ++i) printf("%d\n", q[i]);
return 0;
}int read()
8 30每日總結
分為編譯時的錯誤與執行時的錯誤 處理異常 try和catch trycatch exception e 多個錯誤可以用多個catch 無論是否出現異常都會被執行 修飾符 void fun 引數 throws exception,throw new exception 丟擲異常 throws exce...
8 30 程序管理
1 作業系統基礎 呼叫 kernel通過給應用程式提供system call的方式來提供硬體資源 注意 應用程式也包括庫檔案 庫檔案是執行在ring0上的一段程式 不對客戶直接提 用 2 操作執行原理 乙個程序和多個程序 乙個程序 首先把進硬碟中的程式 載入到記憶體 複製 再將這段程式放到cpu上運...
演算法練習 830 單調棧
830.單調棧 給定乙個長度為n的整數數列,輸出每個數左邊第乙個比它小的數,如果不存在則輸出 1。輸入格式 第一行包含整數n,表示數列長度。第二行包含n個整數,表示整數數列。輸出格式 共一行,包含n個整數,其中第i個數表示第i個數的左邊第乙個比它小的數,如果不存在則輸出 1。資料範圍 1 n 105...