CF559E Gerald and Path

Gerald and Path

有 𝑛 盏灯在数轴上,第 𝑖 盏灯的位置为 𝑎𝑖,照明长度为 𝑙𝑖,每盏灯可以选择往左照或者往右照,如果往左照,则照亮区间 [𝑎𝑖 − 𝑙𝑖, 𝑎𝑖],否则照亮区间[𝑎𝑖, 𝑎𝑖 + 𝑙𝑖]。

最大化被照亮的区间总长。

𝑛 ≤ 100。

题解

https://blog.csdn.net/sz_165394732/article/details/104177077

首先把所有出现的点离散化一下。

因为既要考虑区间的前后关系,又要使一个点的左右两个区间不能同时被选,故需要记录状态\(f[i][j]\)表示前\(i\)个最右覆盖到\(j\)的最长覆盖长度。又因为这样在转移时限制较多比较麻烦,故把\(j\)改为考虑到前\(j\)个位置(\(j\)后面不管)。

设当前点为\((l,p,r)\),转移时,考虑这个点向左还是向右:

  • 向右就由\(f[i-1][p]\)转移到\(f[i][r]\)

  • 向左由于要考虑前面向右的区间可能会伸出去(超过\(r\)),就枚举\(k\),使\(k+1,..,i-1\)都向右,计算一下最右覆盖到哪里,由\(f[k][l]\)转移过来。

该过程用前缀\(\max\)、后缀\(\max\)优化一下即可做到\(O(n^{2})\)

CO int N=310;
struct node {int l,x,r;} a[N];
int p[N],f[N][N],g[N];

int main(){
	int n=read<int>(),m=0;
	for(int i=1;i<=n;++i){
		read(a[i].x); int d=read<int>();
		a[i].l=a[i].x-d,a[i].r=a[i].x+d;
		p[++m]=a[i].l,p[++m]=a[i].x,p[++m]=a[i].r;
	}
	sort(p+1,p+m+1);
	m=unique(p+1,p+m+1)-p-1;
	for(int i=1;i<=n;++i){
		a[i].l=lower_bound(p+1,p+m+1,a[i].l)-p;
		a[i].x=lower_bound(p+1,p+m+1,a[i].x)-p;
		a[i].r=lower_bound(p+1,p+m+1,a[i].r)-p;
	}
	sort(a+1,a+n+1,[&](CO node&a,CO node&b)->bool{
		return a.x<b.x;
	});
	for(int i=1;i<=n;++i){
		int l=a[i].l,x=a[i].x,r=a[i].r;
		copy(f[i-1],f[i-1]+m+1,f[i]);
		fill(g,g+m+1,0);
		// go left
		int mx=x;
		g[mx]=f[i-1][l]+p[mx]-p[l];
		for(int j=i-1;j>=1;--j){
			mx=max(mx,a[j].r);
			g[mx]=max(g[mx],f[j-1][l]+p[mx]-p[l]);
		}
		for(int j=m;j>=l;--j){
			f[i][j]=max(f[i][j],g[j]);
			g[j-1]=max(g[j-1],g[j]-(p[j]-p[j-1]));
		}
		// go right
		for(int j=x;j<=r;++j) f[i][j]=max(f[i][j],f[i-1][x]+p[j]-p[x]);
		for(int j=1;j<=m;++j) f[i][j]=max(f[i][j],f[i][j-1]);
	}
	printf("%d\n",f[n][m]);
	return 0;
}

posted on 2020-04-22 20:47  autoint  阅读(267)  评论(0编辑  收藏  举报

导航