●BZOJ 3126 [Usaco2013 Open]Photo
阿新 • • 發佈:2018-01-02
cst problem 。。 差分 最大 nbsp min string target
然後可以用單調隊列優化。
和普通的單調隊列有點不同,因為多了一個R[i]這個轉移的右端點限制。
題鏈:
http://www.lydsy.com/JudgeOnline/problem.php?id=3126
題解:
單調隊列優化DP,神奇。。
(好像某次考試考過,當時我用了差分約束+SPFA優化,然後過了。。。)
記 L[i] 表示i左邊沒有覆蓋i點的區間中的最大的左端點
R[i] 表示覆蓋i的區間中的最小的左端點的前一個位置,
那麽,如果在i位置放一個點的話,在L[i]~R[i]裏面也必須要放一個點。
(這兩個數組可以O(N)計算前後綴最大最小值得到。)
即定義 DP[i] 為i位置放點時的總點數,
轉移:DP[i]=max(DP[j])+1 (L[i]<=j<=R[i])
然後可以用單調隊列優化。
和普通的單調隊列有點不同,因為多了一個R[i]這個轉移的右端點限制。
其實本質還是相同的~~
考慮到L[i],R[i]都單增,
所以在原來隊列的首尾指針l,r的基礎上多開一個rr指針就好了。
代碼:
#include<cstdio> #include<cstring> #include<iostream> #define MAXN 200050 using namespace std; int L[MAXN],R[MAXN],F[MAXN]; int N,M; int main(){ static int Q[MAXN],l,r,_r; scanf("%d%d",&N,&M); for(int i=1;i<=N+1;i++) R[i]=i-1; for(int i=1,l,r;i<=M;i++){ scanf("%d%d",&l,&r); L[r+1]=max(L[r+1],l); R[r]=min(R[r],l-1); } for(int i=2;i<=N+1;i++) L[i]=max(L[i-1],L[i]); for(int i=N;i>=1;i--) R[i]=min(R[i],R[i+1]); l=_r=r=1; Q[1]=0; for(int i=1;i<=N+1;i++){ while(_r<=R[i]&&_r<=N){ if(F[_r]==-1){_r++; continue;} while(l<=r&&F[Q[r]]<=F[_r]) r--; Q[++r]=_r; _r++; } while(l<=r&&Q[l]<L[i]) l++; if(l<=r) F[i]=F[Q[l]]+(i!=N+1?1:0); else F[i]=-1; } printf("%d",F[N+1]); return 0; }
●BZOJ 3126 [Usaco2013 Open]Photo