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;
}
静渊以有谋,疏通而知事。