NC11253 K.Stack(貪心+拓撲排序)
阿新 • • 發佈:2021-09-30
目錄
Description
有一個單調棧,棧頂最大,記 \(b[i]\) 為 \(a[i]\) 放入棧中後,棧的大小,給出 \(m\) 個 \(b[i]\) ,構造一個 \(a\) 陣列使得 \(b\) 陣列成立(\(a\) 為 $permutation $)
State
\(1<=n<=10^6\)
\(1<=m<=n\)
Input
5 2
2 2
5 4
Output
1 2 5 3 4
Solution
再加入一個元素後,棧內元素個數可以減很多,但是隻能增加一個;
所以如果 \(b[i]=0\), \(b[i]=b[i-1]+1\) 這樣貪心的選取,可以保證之後的 \(b[j]\) 存在
之後, \(b[i]>b[i-1]+1\) 那麼一定是不合法的
\(b[i]=b[i-1]+1\) ,說明 \(a[i]\) 只比棧頂元素小
\(b[i]<b[i-1]+1\), 那麼一直執行出棧操作,直到 \(b[i]=b[j]+1\),在整個過程中, \(a[i]\)
我們可以根據大小關係建一個圖,\(i->j\) 表示 \(j>i\),然後拓撲排序,就可以得到答案了
Code
const int N = 1e6 + 5; int n, m, k, _; int a[N]; int b[N]; stack<pii> s; vector<int> v[N]; int into[N]; void topsort() { queue<int> q; for(int i = 1; i <= n; i ++){ if(into[i] == 0) q.push(i); } int id = 1; while(q.empty() == false){ int u = q.front(); q.pop(); a[u] = id ++; for(auto it : v[u]){ into[it] --; if(into[it] == 0) q.push(it); } } } int main() { //IOS; while(~ sdd(n, m)){ int p, x; while(m -- > 0){ sdd(p, x); b[p] = x; } for(int i = 1; i <= n; i ++){ if(b[i] == 0) b[i] = b[i - 1] + 1; } int ok = 1; for(int i = 1; i <= n; i ++){ if(b[i] - b[i - 1] > 1) ok = 0; } if(! ok){ puts("-1"); continue; } for(int i = 1; i <= n; i ++){ while(! s.empty() && s.top().se >= b[i]){ v[i].pb(s.top().fi); into[s.top().fi] ++; s.pop(); } if(s.empty() == false){ v[s.top().fi].pb(i); into[i] ++; } s.push({i, b[i]}); } topsort(); for(int i = 1; i <= n; i ++){ printf("%d ", a[i]); } } //PAUSE; return 0; }