CF559E Gerald and Path

STO CXR ORZ

首先套路地把所有关键点离散化,并且把所有线段按照端点从小到大排序

我们发现我们可以把一条线段\([l,r]\)拆成\([l,l],[l,l+1],\cdots,[l,r]\),此时我们就可以强制每条线段不相交了

\(f_{i,j}\)表示前\(i\)条线段,上一条的右端点最远在\(j\)的最大覆盖,考虑每条线段的情况无非是两种选择:

  • 向右,这种情况非常简单,直接大力转移即可
  • 向左,主要要考虑在之前的点中存在一条线段的右端点超过当前点。我们可以枚举一个分界点,强制左边的不会超过这个分界点,并且右边的强制向右求出最远的位置

考虑这样做的正确性,假设存在反例的话就是存在一个点在分界点左侧选择向右,一个点在分界点右侧选择向左

但是画一画我们发现这样一定不如改成在分界点左侧选择向左,一在分界点右侧选择向右更优,于是正确性得证

总复杂度\(O(n\log n)\)

#include<cstdio>
#include<iostream>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=105;
struct element
{
	int p,l;
	friend inline bool operator < (const element& A,const element& B)
	{
		return A.p<B.p;
	}
}a[N]; int n,rst[3*N],cnt,f[N][3*N],mr[N][N];
inline int find(CI x)
{
	return lower_bound(rst+1,rst+cnt+1,x)-rst;
}
int main()
{
	RI i,j,k; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d%d",&a[i].p,&a[i].l),
	rst[++cnt]=a[i].p,rst[++cnt]=a[i].p-a[i].l,rst[++cnt]=a[i].p+a[i].l;
	sort(rst+1,rst+cnt+1); cnt=unique(rst+1,rst+cnt+1)-rst-1;
	for (sort(a+1,a+n+1),i=1;i<=n;++i)
	for (mr[i][i]=find(a[i].p+a[i].l),j=i+1;j<=n;++j)
	mr[i][j]=max(mr[i][j-1],find(a[j].p+a[j].l)); for (i=1;i<=n;++i)
	{
		int pos=find(a[i].p),l=find(a[i].p-a[i].l),r=find(a[i].p+a[i].l);
		for (j=r;j>=pos;--j) f[i][j]=max(f[i][j],f[i-1][pos]+rst[j]-rst[pos]);
		for (j=1;j<=i;++j) for (k=max(pos,mr[j][i-1]);k>=l;--k)
		f[i][k]=max(f[i][k],f[j-1][l]+rst[k]-rst[l]);
		for (j=1;j<=cnt;++j) f[i][j]=max(f[i][j],f[i-1][j]),f[i][j]=max(f[i][j],f[i][j-1]);
	}
	return printf("%d",f[n][cnt]),0;
}
posted @ 2020-12-03 20:51  空気力学の詩  阅读(69)  评论(0编辑  收藏  举报