zoukankan      html  css  js  c++  java
  • [洛谷P4563][JXOI2018]守卫

    题目大意:有一段$n(nleqslant5 imes10^3)$个点的折线,特殊点可以覆盖它以及它左边的它可以“看见”的点(“看见”指连线没有其他东西阻挡)。定义$f_{l,r}$为区间$[l,r]$最少需要的特殊点个数,求:$sumlimits_{l=1}^nsumlimits_{r=l}^nf_{l,r}$

    题解:可以用斜率来判断是否可以看见。发现$r$一定要设一个关键点,而若一个极大区间$[l',r']$在$r$处看不见,那么一定要在$r'$或$r'+1$处设一个关键点,所以$f_{l,r}=1+sumlimits_{l',r'}min{f_{l',r'},f_{l',r'+1}}$($l',r'$即为上文说的极大看不见的区间)

    但这样复杂度是$O(n^3)$,不能承受,发现固定了$r$后(固定$l$也行),那些看不见的区间是重复的,可以后缀处理(固定$l$就是前缀)。

    卡点:开始$naive$的以为贪心就行了(原以为直接贪心选择$r'+1$即可,然后发现一个斜率降低的折线就挂了)

    C++ Code:

    #include <algorithm>
    #include <cstdio>
    #define maxn 5010
    const double inf = 1e9;
    
    int n, ans;
    int h[maxn], f[maxn][maxn];
    inline double slope(int l, int r) {
    	if (l == r) return inf;
    	return (h[r] - h[l]) / static_cast<double> (r - l);
    }
    int main() {
    	scanf("%d", &n);
    	for (int i = 1; i <= n; ++i) scanf("%d", h + i);
    	for (int r = 1, sum, now; r <= n; ++r) {
    		ans ^= (sum = f[r][r] = 1);
    		now = r;
    		for (int l = r - 1; l; --l) {
    			if (slope(l, r) < slope(now, r)) {
    				sum += std::min(f[l + 1][now - 1], f[l + 1][now]);
    				now = l;
    			}
    			ans ^= (f[l][r] = sum + std::min(f[l][now - 1], f[l][now]));
    		}
    	}
    	printf("%d
    ", ans);
    	return 0;
    }
    

      

  • 相关阅读:
    element ui源码解析 -- button篇
    如何在vue项目中使用百度编辑器ueditor
    基于element ui的图片预览插件
    jquery weui日期选择控件添加取消按钮
    swiper如何实现轮播嵌套轮播
    jQuery weui Select组件显示指定值
    vue打包静态资源路径不正确的解决办法
    CSS垂直居中的实现
    vue学习笔记二:v-if和v-show的区别
    vue学习笔记一:用Key管理可复用元素
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/10349166.html
Copyright © 2011-2022 走看看