CF1399F Yet Another Segments Subset 題解
阿新 • • 發佈:2022-05-28
把貢獻看成邊,那麼會形成一個樹形結構。有一個做法就是在樹上做 dp 然後樹狀陣列優化,\(O(n^2\log n)\)。
我的做法是,考慮一個區間 dp,設 \(f_{l,r}\) 表示所有在 \([l,r]\) 內的線段最多選多少個,這樣就有一個 \(O(n^3)\) 的 dp。考慮什麼情況的轉移是有用的:對於區間 \([l,r]\) 來說,只有左端點在 \(l\) 和右端點在 \(r\) 的線段的端點是可以轉移的。每個線段只會在 \(O(n)\) 個區間轉移,所以複雜度 \(O(n^2)\)。
還有一個常數優化是,其實只需要管左端點在 \(l\) 的,剩下的那種情況一定能求到。
點選檢視程式碼
#include<cstdio> #include<algorithm> #include<vector> #define pb push_back inline int max(const int &a,const int &b){return a>b?a:b;} const int N=6000+13; struct Node{int l,r;}a[N]; int n,b[N],f[N][N]; std::vector<int> g[N]; int main(){int T;scanf("%d",&T);while(T--){ scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d%d",&a[i].l,&a[i].r); b[i*2-1]=a[i].l,b[i*2]=a[i].r; } std::sort(b+1,b+n*2+1);int tt=std::unique(b+1,b+n*2+1)-b-1; for(int i=1;i<=tt;++i) g[i].clear(); for(int i=1;i<=tt;++i) for(int j=i;j<=tt;++j) f[i][j]=0; for(int i=1;i<=n;++i){ int l=std::lower_bound(b+1,b+tt+1,a[i].l)-b; int r=std::lower_bound(b+1,b+tt+1,a[i].r)-b; f[l][r]=1;g[l].pb(r); } for(int i=1;i<=tt;++i) std::sort(g[i].begin(),g[i].end()); for(int l=tt-1;l;--l){ for(int r=l+1;r<=tt;++r){ int tmp=max(f[l+1][r],f[l][r-1]); for(int i=0,lim=g[l].size();i<lim;++i){ int p=g[l][i]; if(p+1<=r) tmp=max(tmp,f[l][p]+f[p+1][r]); else break; } f[l][r]+=tmp; } } printf("%d\n",f[1][tt]); } return 0; }