這題的關鍵是注意到,如果有 x < y < z ,滿足 x 和 y 連邊,且 y 和 z 連邊,那麼 x 就和 z 連邊,證明並不難。因此我們只要找一個最長的子序列,使得相鄰的兩個點都有連邊就可以了。而這顯然可以DP,設 dp[ i ] 代表以 i 結尾的最長相鄰兩點有連邊的最長子序列的長度,那麼可以用 dp[ j ] 轉移 dp[ i ] 的條件就是 w[ i ] + w[ j ] <= p[ i ] - p[ j ] ,移項得 p[ i ] - w[ i ] >= w[ j ] + p[ j ] ,因此對於每個 j ,紀錄一個二元組 ( dp[ j ] , w[ j ] + p[ j ] ) ,並且可以知道,如果一個數的 dp 值比較小,但 w + p 的值比較大,那麼他就廢掉了,因此可以維護一個兩個座標都是遞增的二元組的 set ,查詢時對他查詢比 p[ i ] - w[ i ] 小的最大 w[ j ] + p[ j ] 值,他的 dp 值 +1 就是這個數的 dp 值。
code :
#include<bits/stdc++.h> #define INF 1500000000 using namespace std; const int maxn=200000+10 ; struct P { int x,y ; bool operator < (const P &rhs) const { return x==rhs.x ? y>rhs.y : x<rhs.x ; } }; set<P> st ; void insert(const P &p) { st.insert(p) ; auto it=st.find(p) ; bool keep=1 ; if(it!=st.begin()) { it-- ; if(it->y >= p.y) keep=0 ; it++ ; } if(!keep) { st.erase(it) ; return ; } while(1) { auto it2=it ; it2++ ; if(it2!=st.end() && it2->y<=p.y) st.erase(it2) ; else break ; } } P a[maxn] ; main() { int n ; scanf("%d",&n) ; for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y) ; sort(a+1,a+n+1) ; insert((P){-INF,0}) ; int ans=0 ; for(int i=1;i<=n;i++) { auto it=st.upper_bound((P){a[i].x-a[i].y,-INF}) ; it-- ; int val=it->y+1 ; ans=max(ans,val) ; insert((P){a[i].x+a[i].y,val}) ; } printf("%d\n",ans) ; }
沒有留言:
張貼留言