题解:P4563 [JXOI2018] 守卫
复出之后做的第一道区间 DP。
话说控制欲这么强的嘛。
Solution
区间问题,考虑区间 DP。设
首先可以发现,对于一段区间
然后画个图,你可以发现,若亭子
可以发现上图的红色实线的连到的亭子全都可以被看到,而虚线的亭子
设
那么必须放守卫来看守这一段了。假设我们在一个
这时就出问题了,你会发现
所以我们得出一个结论:放置守卫的位置不能超过
那么转移就很显然了,处理出所有
于是
考虑优化这个区间 DP。考虑固定右端点
所以设
所以 DP 就被优化成了
可以说这题让刚复出的我对最优子结构的理解大大提升,对最优子结构的利用可谓是淋漓尽致。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5000 + 10;
int n;
ll ans, h[N], f[N][N];
bool can_be_see(int x, int now, int r){//x的斜率比now的斜率小,就可以被看到
return (h[r] - h[x]) * 1ll * (r - now) < (h[r] - h[now]) * 1ll * (r - x);
}//斜率公式:(x1 - x2) / (y1 - y2),不过除法改乘法了而已
int main(){
scanf("%d", &n);
for(int i=1;i<=n;i++)
scanf("%d", &h[i]);
for(int r=1;r<=n;r++){
int p = 0;
ans ^= (f[r][r] = 1);//这个显然嘛
for(int l=r-1;l>=1;l--){
if(!p || can_be_see(l, p, r))
p = l;
f[l][r] = min(f[l][p - 1], f[l][p]) + f[p + 1][r];
ans ^= f[l][r];
}
}
printf("%lld\n", ans);
return 0;
}