首先我们令三个点x<y<r(r为区间l到r的r)。可以发现,只有 K x r < K y r Kxr<Kyr Kxr<Kyr才能保证x与y都能被看到。
我们定义dp数组为l到r之间都监视完所需的最小守卫个数。
再设x为当前走到的最后能被r看到的点。可以证明在x或x-1点放守卫最优。(画个图就行了)
然后我们知道,2个r可以看到的点x,y,他们之间的点可能并不会被r看到。所以在计算dp[l][r]时,我们还要累加min(dp[x+1][y],dp[x+1][y-1])。(为什么不是用分开的dp式表示?这已经是前面的最优答案)
#include<cstdio>
#include<iostream>
using namespace std;
const int N = 5002, limit = (1 << 30) - 1;
int n, h[N], ans, dp[N][N];
double slope(const int x, const int y) {
if(x == y)
return limit;
return (double) (h[x] - h[y]) / (double) (x - y);
}
int main() {
int sum, L;
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
scanf("%d", &h[i]);
for(int r = 1; r <= n; r ++) {
ans ^= 1;
dp[r][r] = 1;//r点必须放置一个守卫
sum = 1;
L = r;
for(int l = r - 1; l >= 1; l --) {
if(slope(l, r) < slope(L, r)) {
sum += min(dp[l + 1][L], dp[l + 1][L - 1]);
L = l;
}
dp[l][r] = sum + min(dp[l][L], dp[l][L - 1]);
ans ^= dp[l][r];
}
}
printf("%d\n", ans);
return 0;
}
Bye~