【JXOI 2018】守卫

首先我们令三个点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~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值