1. 程式人生 > 實用技巧 >《Codeforces Round #669 (Div. 2)》

《Codeforces Round #669 (Div. 2)》

D:其實這個題目沒有那麼難(但還是挺難的

首先顯然是一個單調佇列或者單調棧優化的dp。

主要是怎麼去優化,這裡一開始想單調佇列想了好久都沒想清楚。

Solution:我們可以去維護一個單調遞減和單調遞增的棧。

對於單調遞增棧來說。

因為是單調遞增,所以當a[i] < a[top]時。

我們就可以邊退棧變更新。因為每一次退棧時都滿足之前退的元素 > a[i]和a[top],那麼顯然就能更新出。

注意我們退完後的棧頂,剛好也是滿足之前退棧的元素全都 > a[i]和a[top]的。所以對棧頂再求一次最小的dp。

那麼也可以發現,我們中間退棧的時候需要保持嚴格的大於才能退棧。

那麼也就會導致我們棧中可能會有連續重複的元素,這時顯然要無法滿足更新條件,因為中間都相同的話也不滿足條件。

所以我們要對相同的也進行退棧。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 3e5+5;
const int M = 2e5+5;
const LL Mod = 1e9+7;
#define rg register
#define pi acos(-1)
#define INF 1e9
#define CT0 cin.tie(0),cout.tie(0)
#define IO ios::sync_with_stdio(false)
#define
dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3
)+(c^48);c = getchar();} return x*f; } void print(int x){ if(x < 0){x = -x;putchar('-');} if(x > 9) print(x/10); putchar(x%10+'0'); } } using namespace FASTIO; int a[N],dp[N],S1[N],S2[N];//遞減棧,遞增棧 int main() { int n;n = read(); for(rg int i = 1;i <= n;++i) a[i] = read(); memset(dp,0x3f,sizeof(dp)); dp[1] = 0; int top1 = 0,top2 = 0; S1[++top1] = 1,S2[++top2] = 1; for(rg int i = 2;i <= n;++i) { dp[i] = min(dp[i],dp[i-1]+1); while(top1 != 0 && a[i] > a[S1[top1]]) dp[i] = min(dp[i],dp[S1[top1--]]+1); if(top1 != 0) dp[i] = min(dp[i],dp[S1[top1]]+1); while(top1 != 0 && a[S1[top1]] == a[i]) top1--; S1[++top1] = i; while(top2 != 0 && a[i] < a[S2[top2]]) dp[i] = min(dp[i],dp[S2[top2--]]+1); if(top2 != 0) dp[i] = min(dp[i],dp[S2[top2]]+1); while(top2 != 0 && a[S2[top2]] == a[i]) top2--; S2[++top2] = i; } //for(rg int i = 1;i <= n;++i) printf("dp[%d] is %d\n",i,dp[i]); printf("%d\n",dp[n]); }
View Code