CF1407D Discrete Centrifugal Jumps 題解
阿新 • • 發佈:2020-09-14
蒟蒻語
寫了 \(100\) 行的 線段樹上ST表維護二分維護單調棧維護dp, 結果最後發現只要倆單調棧就好了 = =
蒟蒻解
首先 \(dp_i\) 表示從 \(1\) 樓到 \(i\) 樓要跳幾次。
題目中有 3 個條件, 對三個條件分別設 \(dp\) 方程。
第一個很顯然, 就是 : \(dp_i = dp_{i - 1} + 1\)
第二個怎麼弄呢?
考慮看有哪些點是可能來更新這個點的。
假設 \(x\) 位置可以來更新 \(i\) 位置。那麼 \(h_x > max(h_x, h_{x + 1} ... h_{i - 1})\)。
考慮使用單調棧。單調棧裡面的節點滿足嚴格遞增。
那麼又因為要求 \(h_i > max(h_x, h_{x + 1} ... h_{i - 1})\)
可以在單調棧中邊彈點變更新答案。
第三個條件和第二個幾乎一樣,不說了。
蒟蒻碼
細節看程式碼吧。
#include<bits/stdc++.h> using namespace std; const int N = 3e5 + 7; int n, m, s[N], dp[N], atot, a[N], btot, b[N]; int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &s[i]); memset(dp, 0x3f, sizeof(dp)); a[++atot] = 1, b[++btot] = 1, dp[1] = 0; for(int i = 2; i <= n; i++) { dp[i] = dp[i - 1] + 1; while(atot && s[i] >= s[a[atot]]) { if(s[i] != s[a[atot]]) dp[i] = min(dp[i], dp[a[atot - 1]] + 1); --atot; } while(btot && s[i] <= s[b[btot]]) { if(s[i] != s[b[btot]]) dp[i] = min(dp[i], dp[b[btot - 1]] + 1); --btot; } a[++atot] = i, b[++btot] = i; } printf("%d\n", dp[n]); return 0; }