1. 程式人生 > 其它 >Deltix Round, Summer 2021 (open for everyone, rated, Div. 1 + Div. 2)C. Compressed Bracket Sequence

Deltix Round, Summer 2021 (open for everyone, rated, Div. 1 + Div. 2)C. Compressed Bracket Sequence

傳送門

括號序列肯定想到要轉化成折線考慮,這個是經典操作就不解釋了,想學的看這裡有解釋

(當然如果是比較短的括號序列求子合法序列可以用棧配合 dp 算,比如某道使我提前退役的題目

這一題因為序列是壓縮的,沒法用一般的 dp 算

對於折線下降的某個位置,要算左邊包含同高度的上升段數(且之間沒有更低的折線段)

如圖說明的一樣:

注意到段數 $n<=1000$ ,所以容易想到可以對每一下降段作為右端點,列舉前面的所有上升段作為左端點然後計算

要注意一種情況的處理:

具體看程式碼吧,實現起來挺噁心的,記得$long$ $long$

#include<iostream>
#include
<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; typedef long long ll; const int N=2e5+7; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='
9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } int n; ll r[N];//維護每一段的右端點 ll ans; ll cal(ll x,ll y,ll p,ll q)//求區間 [x,y] 和區間 [p,q] 的交集大小 { if(p>q||x>y) return 0; if(x>q||y<p||p>y||q<x) return 0; if(x<=p&&y<=q) return y-p+1; if(p<=x&&q<=y) return
q-x+1; if(x>=p&&y<=q) return y-x+1; if(x<=p&&y>=q) return q-p+1; } int main() { n=read(); int c; for(int i=1;i<=n;i++) { c=read(); if(i&1) r[i]=r[i-1]+c; else r[i]=r[i-1]-c;//判斷段是上升還是下降 if(i&1) continue;//只以下降段位右端點 ll x=r[i],y=r[i-1];//確定下降段的區間 ll p=r[i-2],q=r[i-1];//對左邊第一個上升段特判,因為左邊第一段的右端點和當前下降段左端點重合 ans+=cal(x,y,p,q)-1;//注意-1 for(int j=i-3;j>0;j-=2)//找更前面的上升段 { //p,q維護當前上升段的合法區間 if(r[j-1]>p) continue;//這個特判很關鍵,自己畫圖理解qwq q=min(q,p); p=min(p,r[j-1]);//這個p,q的更新可以參考我的圖 ans+=cal(x,y,p,q);//累加答案 } } printf("%lld\n",ans); return 0; }