1. 程式人生 > >[USACO 08MAR]土地購買 Land Acquisition

[USACO 08MAR]土地購買 Land Acquisition

註意 輸出格式 show tps 技術分享 絕對值最小 integer nec describe

[USACO08MAR] 土地購買 Land Acquisition


1.題目

題目描述

約翰準備擴大他的農場,眼前他正在考慮購買N塊長方形的土地。如果約翰單買一塊土地,價格就是土地的面積。但他可以選擇並購一組土地,並購的價格為這些土地中最大的長乘以最大的寬。比如約翰並購一塊3 × 5和一塊5 × 3的土地,他只需要支付5 × 5 = 25元, 比單買合算。 約翰希望買下所有的土地。他發現,將這些土地分成不同的小組來並購可以節省經費。 給定每份土地的尺寸,請你幫助他計算購買所有土地所需的最小費用。

輸入輸出格式

輸入格式:

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\)

輸出格式:

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

輸入輸出樣例

輸入樣例#1:

復制

4 
100 1 
15 15 
20 5 
1 100 

輸出樣例#1:

500 

說明

There are four plots for sale with dimensions as shown.

The first group contains a 100x1 plot and costs 100. The next group contains a 1x100 plot and costs 100. The last group contains both the 20x5 plot and the 15x15 plot and costs 300. The total cost is 500, which is minimal.

2.題解

這題可以使用斜率優化。設長為\(l\),寬為\(r\)

技術分享圖片

當考慮矩形1與矩形2組合時,則花費為\(l1 \times r2\)。需要額外承擔的花費為\((l1 - l2) * (r2 - r1)\)。所以在轉移時我們需要考慮兩正方形之間長與寬的差的絕對值最小。所以按照先長升序後寬升序排序。

這樣我們就得到了一個長遞增,寬之間關系不確定的序列。再考慮當\(i > j\),若\(l_{i} > l_{j}\)\(w_{i} > w_{j}\),則矩形\(i\)一定包含矩形\(j\)。這樣我們可以預處理一下,將被包含的矩形去除掉,不需要再DP。這樣,在矩形\(i\)

前且\(w_{j} < w_{i}\)的矩形就被處理沒了,我們就獲得了一個長遞增,寬遞減的序列,轉移式就非常好寫了。
\[ F[i] = F[j] + l_{i} * w_{j + 1}\B = y - kx\y = F[j] \ \ \ \ \ k = -l_{i}\ \ \ \ \ x = w_{j + 1} \]

#include <algorithm>
#include <cstdio>
typedef long long ll;
const int MAXN = 50010;
struct LAND{
    int l, w;
}a[MAXN];
int n, tmpn;
ll f[MAXN];
inline bool cmp(LAND a, LAND b) {       //排序
    return (a.l == b.l ? a.w < b.w : a.l < b.l);
}
inline double slope(int i, int j) {
    return ((f[j] - f[i]) / (1.0 * (a[j + 1].w - a[i + 1].w)));
}
struct QUEUE {
    int head, tail;
    int q[MAXN];
    QUEUE() {head = tail = 0;}
    void clean() {head = tail = 0;}
    void push(int x) {          //斜率是負數,所以與普通下凸包維護操作不同
        while(head <= tail && slope(q[tail], x) > slope(q[tail - 1], q[tail])) tail--;
        q[++tail] = x;
    }
    int pop(int i) {
        int tmp = -a[i].l;
        while(head < tail && slope(q[head], q[head + 1]) > tmp) head++;
        return q[head];
    }
}que;
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
        scanf("%d%d", &a[i].w, &a[i].l);
    std::sort(a + 1, a + n + 1, cmp);
    for (int i = 1; i <= n; ++i) {      //處理被包含的矩形
        while(tmpn && a[tmpn].w <= a[i].w) tmpn--;
        a[++tmpn] = a[i];
    }
    n = tmpn;
    for (int i = 1; i <= n; ++i) {
        int j = que.pop(i);
        f[i] = f[j] + (ll)a[i].l * a[j + 1].w;
        que.push(i);
    }
    printf("%lld\n", f[n]);
    return 0;
}

因為斜率是負數,所以雖然要維護下凸包,但是\(slope(tail, i) < slope(tail - 1,tail)\)\(slope(head, head+1) < k\)我就栽在這裏了一定要註意。

[USACO 08MAR]土地購買 Land Acquisition