• 洛谷1792 [国家集训队]种树(wqs二分)


    洛谷1792 [国家集训队]种树(wqs二分)

    题目描述

    ​ A 城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。

    ​ 园林部门得到指令后,初步规划出 n 个种树的位置,顺时针编号 1 到 n。并且每个位置都有一个美观度 Ai ,如果在这里种树就可以得到这Ai的美观度。但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置( i 号位置和 i+1 号位置叫相邻位置。值得注意的是 1 号和 n 号也算相邻位置!)。

    最终市政府给园林部门提供了 m 棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大。如果无法将 m 棵树苗全部种上,给出无解信息。

    数据范围

    (1 le n le 200000)

    解题思路

    种树要浇忘情水

    一眼看上去就是 dp 啊QAQ

    先解决环对后效性的干扰,考虑 1 号点种不种树,种的话就是 ([3, n-1]) 一条链,不种就是 ([2, n]) 的一条链

    考虑暴力 dp,(f[i][j]) 表示前 i 个位置,种了 j 棵树的最大值是多少,有

    [f[i][j] = max(f[i-1][j], f[i-2][j-1] + a[i]) ]

    显然过不去,不难臆想出答案随着种树的棵数变化是单峰的,考虑忘情水二分

    然后就没了~

    template <typename T>
    inline void Mx(T &x, T y) { x < y && (x = y, 0); }
    
    const int N = 200050;
    struct DP {
    	ll val, cnt;
    	bool operator < (DP b) {
    		return val < b.val;
    	}
    	DP operator + (DP b) {
    		return (DP){val + b.val, cnt + b.cnt};
    	}
    }f[N];
    
    bool check(int del, int n, int m, int *a) {
    	f[1] = (DP) {a[1] + del, 1}; Mx(f[1], f[0]);
    	for (int i = 2;i <= n; i++) {
    		f[i] = f[i-2] + (DP) {a[i] + del, 1};
    		Mx(f[i], f[i-1]);
    	}
    	return f[n].cnt >= m;
    } 
    
    ll work(int n, int m, int *a) {
    	ll l = -200000, r = -l;
    	while (l <= r) {
    		ll mid = (l + r) >> 1;
    		if (check(mid, n, m, a)) r = mid - 1;
    		else l = mid + 1; 
    	}
    	check(l, n, m, a); //此处注意要用l, 因为我更新的时候 cnt 可能取不到 m 而偏大
    	return f[n].val - l * m;
    }
    
    int a[N];
    int main() {
    	int n, m; read(n), read(m);
    	if (m > n/2) return puts("Error!"), 0;
    	for (int i = 1;i <= n; i++) read(a[i]);
    	write(max(a[1] + work(n - 3, m - 1, a + 2), work(n - 1, m, a + 1)));
    	return 0;
    }
    
  • 相关阅读:
    MySQL中mysqldump导出数据的使用
    MySQL中show语法使用总结
    Nginx配置项优
    Elasticsearch5.2.2安装
    SSH实现双向认证
    MySQL5.6主从复制搭建基于日志(binlog)
    清除Pycharm设置的方法
    Python3编程技巧
    django组件-中间件
    Python打杂之路
  • 原文地址:https://www.cnblogs.com/Hs-black/p/12931043.html
Copyright © 2020-2023  润新知