cunzai_zsy0531

关注我

CF1399F Yet Another Segments Subset 题解

把贡献看成边,那么会形成一个树形结构。有一个做法就是在树上做 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;
}
posted @ 2022-05-28 14:59  cunzai_zsy0531  阅读(57)  评论(0编辑  收藏  举报