Codeforces Contest 1083 problem E The Fair Nut and Rectangles —— 斜率优化DP

The Fair Nut got stacked in planar world. He should solve this task to get out.

You are given n rectangles with vertexes in (0,0), (xi,0), (xi,yi), (0,yi). For each rectangle, you are also given a number ai. Choose some of them that the area of union minus sum of ai of the chosen ones is maximum.

It is guaranteed that there are no nested rectangles.

Nut has no idea how to find the answer, so he asked for your help.

Input
The first line contains one integer n (1≤n≤106) — the number of rectangles.

Each of the next n lines contains three integers xi, yi and ai (1≤xi,yi≤109, 0≤ai≤xi⋅yi).

It is guaranteed that there are no nested rectangles.

Output
In a single line print the answer to the problem — the maximum value which you can achieve.

Examples
inputCopy
3
4 4 8
1 5 0
5 2 10
outputCopy
9
inputCopy
4
6 2 4
1 6 2
2 4 3
5 3 8
outputCopy
10
Note
In the first example, the right answer can be achieved by choosing the first and the second rectangles.

In the second example, the right answer can also be achieved by choosing the first and the second rectangles.

题意:

给你一些从0,0开始向右的矩形,保证没有任意两个矩形有包含关系,每个矩形都有一个值ai,让你任意选一些矩形使得他们所占区域的交集减去他们所有a的和,使得这个值最大。

扫描二维码关注公众号,回复: 5774113 查看本文章

题解:

第一次接触斜率dp,听别人给我讲的,说是一眼题,我们可以根据他给的条件列出一个方程组:
dp[i]=dp[j]+(xi-xj)yi-ai;
dp[i]=dp[k]+(xi-xk)yi-ai;
这两个方程组相减并消去同类项得dp[j]-dp[k]+yi
(xjkxj)
如果j比k更优,那么dp[j]-dp[k]+yi
(xk-xj)>0
得(dp[j]-dp[k])/(xj-xk)>yi
那么这就是一个类似log的凸包
在这里插入图片描述
假设刚开始有两个黑点,如果新来一个红点,与他们组成的斜率如图,那么既然在上一个状态的时候k3被保留了,说明红点肯定比所有黑点更优,因为它的斜率最大,那,饿现在就只剩下一个点了。
在这里插入图片描述
如果新来的红点是长这个样子的,那么k2就比k1小,但是由于这道题特殊的性质,下一个y是越来越小的,所以红点要先保留,那么这个图就变成了类似log的曲线,那么我们找的时候只需要看当前的和下一个点的斜率是否大于yi,如果大于就说明还可能可以往后,那么sta++,对于维护这个图包,如果新来的点比前面的斜率更大,那就把前面的去掉,也就是en–。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+5;
struct node
{
    ll x,y,a;
    bool operator< (const node& b)const
    {
        return x<b.x;
    }
}re[N];
int q[N];
ll dp[N];
double cal(int x,int y)
{
    return 1.0*(dp[x]-dp[y])/(re[x].x-re[y].x);
}
int judge(int x,int y,int z)
{
    return cal(y,z)>re[x].y;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld%lld%lld",&re[i].x,&re[i].y,&re[i].a);
    sort(re+1,re+1+n);
    ll ans=0;
    int sta=0,en=0;
    for(int i=1;i<=n;i++)
    {
        while(sta<en&&judge(i,q[sta+1],q[sta]))
            sta++;
        dp[i]=dp[q[sta]]+(re[i].x-re[q[sta]].x)*re[i].y-re[i].a;
        ans=max(ans,dp[i]);
        while(en>sta&&cal(i,q[en])>cal(q[en],q[en-1]))
            en--;
        q[++en]=i;
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/88887774