• P2900 [USACO08MAR]土地征用Land Acquisition


    (color{#0066ff}{ 题目描述 })

    约翰准备扩大他的农场,眼前他正在考虑购买N块长方形的土地。如果约翰单买一块土 地,价格就是土地的面积。但他可以选择并购一组土地,并购的价格为这些土地中最大的长 乘以最大的宽。比如约翰并购一块3 × 5和一块5 × 3的土地,他只需要支付5 × 5 = 25元, 比单买合算。 约翰希望买下所有的土地。他发现,将这些土地分成不同的小组来并购可以节省经费。 给定每份土地的尺寸,请你帮助他计算购买所有土地所需的最小费用。

    (color{#0066ff}{输入格式})

    Line 1: A single integer: N

    Lines 2..N+1: Line i+1 describes plot i with two space-separated integers: (width_i) and (length_i)

    (color{#0066ff}{输出格式})

    Line 1: The minimum amount necessary to buy all the plots.

    (color{#0066ff}{输入样例})

    4 
    100 1 
    15 15 
    20 5 
    1 100 
    

    (color{#0066ff}{输出样例})

    500 
    

    (color{#0066ff}{数据范围与提示})

    none

    (color{#0066ff}{题解})

    首先可以发现,对于两个矩形, 如果一个可以完全包含另一个,完全可以让这两个一组,这样那个小的矩形就没贡献了,可以删掉

    按长为第一关键字,宽为第二关键字从小到大排序

    倒着扫一遍,维护max宽,如果当前矩形的宽小于max宽,又因为排序一定小于长

    所以当前矩形就没用了,否则放入一个新的数组里

    翻转一下可以发现

    这个数组的矩形,长递增,宽递减

    最优的分组一定是几个连续的区间

    可以发现一个区间的价值是l的长和r的宽

    如果不连续,那么价值要比这个大

    所以就可以DP了

    (f[i] = f[j-1]+i_a*j_b)

    (i_a)作为斜率移到左边,因为是负的,而且还要维护最小值,斜率应为正的

    可以直接取正的维护最大值然最后取反就行了

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; int x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    const int maxn = 50505;
    using std::pair;
    using std::make_pair;
    pair<LL, LL> mp[maxn], a[maxn];
    int cnt;
    LL f[maxn];
    LL X(int x) { return a[x + 1].second; }
    LL Y(int x) { return f[x]; }
    double K(int x, int y) { return (double)(Y(x) - Y(y)) / (double)(X(x) - X(y)); }
    int main() {
    	int n = in();
    	for(int i = 1; i <= n; i++) mp[i].first = in(), mp[i].second = in();
    	std::sort(mp + 1, mp + n + 1);
    	LL max = 0;
    	for(int i = n; i >= 1; i--) {
    		if(mp[i].second > max) a[++cnt] = mp[i];
    		max = std::max(max, mp[i].second);
    	}
    	std::reverse(a + 1, a + cnt + 1);
    	static int q[maxn], head, tail;
    	for(int i = 1; i <= cnt; i++) {
    		LL k = a[i].first;
    		while(head < tail && k > K(q[head], q[head + 1])) head++;
    		f[i] = f[q[head]] - a[i].first * a[q[head] + 1].second;
    		while(head < tail && K(q[tail], q[tail - 1]) > K(i, q[tail - 1])) tail--;
    		q[++tail] = i;
    	}
    	printf("%lld
    ", -f[cnt]);
    	return 0;
    }
    
  • 相关阅读:
    好友消息和群消息区别
    好友消息和群消息区别
    完整的微信登陆 接收消息流程
    完整的微信登陆 接收消息流程
    perl 对象 通过bless实现
    perl 对象 通过bless实现
    00019_数组的定义
    关于tinymce粘贴图片自动上传
    关于kindeditor粘贴图片自动上传
    关于ckeditor粘贴图片自动上传
  • 原文地址:https://www.cnblogs.com/olinr/p/10227089.html
Copyright © 2020-2023  润新知