[USACO08MAR]土地购买

本文介绍了一种通过排序和动态规划解决二维矩形区域划分问题的高效算法,通过去除冗余块并利用单调队列优化转移过程,实现了O(n)的时间复杂度。

一、题目

点此看题

二、解法

首先考虑如果有一个块长和宽都比另一个块要小,那么这个块就没有存在的意义了,我们可以先排序(长为第一关键字,宽为第二关键字,从小到大),然后从后往前扫,期间维护宽的最大值,如果最大值不比当前宽小,那么这个块没用,我们去除完没用的点之后再排一遍序(方法一样)。

这样就可以愉快的 d p dp dp了,设 d p [ i ] dp[i] dp[i]为划分到 i i i的最小花费,转移如下:
d p [ i ] = d p [ j ] + a [ i ] × b [ j + 1 ] dp[i]=dp[j]+a[i]\times b[j+1] dp[i]=dp[j]+a[i]×b[j+1]转移是 O ( n 2 ) O(n^2) O(n2)的,我们来推一波式子,设两个转移点 j , k j,k j,k j < k j<k j<k):
d p [ j ] + a [ i ] × b [ j + 1 ] < d p [ k ] + a [ i ] × b [ k + 1 ] dp[j]+a[i]\times b[j+1]<dp[k]+a[i]\times b[k+1] dp[j]+a[i]×b[j+1]<dp[k]+a[i]×b[k+1] d p [ j ] − d p [ k ] − b [ j + 1 ] + b [ k + 1 ] < a [ i ] \frac{dp[j]-dp[k]}{-b[j+1]+b[k+1]}<a[i] b[j+1]+b[k+1]dp[j]dp[k]<a[i]显然 a [ i ] a[i] a[i]是单调递增的, − b [ i ] -b[i] b[i]也是单调递增的,队首维护上面的式子,队尾保证斜率单调递增,时间复杂度 O ( n ) O(n) O(n),贴个代码。

#include <cstdio>
#include <algorithm>
using namespace std;
#define int long long
const int M = 50005;
int read()
{
    int x=0,flag=1;
    char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,m,mx,h,t,dp[M],q[M];
struct node
{
    int a,b;
    node(int A=0,int B=0) : a(A) , b(B) {}
    bool operator < (const node &B) const
    {
        if(a==B.a) return b<B.b;
        return a<B.a;
    }
}s[M],v[M];
int up(int j,int k)
{
    return dp[j]-dp[k];
}
int down(int j,int k)
{
    return v[k+1].b-v[j+1].b;
}
signed main()
{
    n=read();
    for(int i=1;i<=n;i++)
        s[i]=node(read(),read());
    sort(s+1,s+1+n);
    for(int i=n;i>=1;i--)
    {
        if(s[i].b<=mx) continue;
        mx=max(mx,s[i].b);
        v[++m]=s[i];
    }
    sort(v+1,v+1+m);
    for(int i=1;i<=m;i++)
    {
        while(h<t && up(q[h+1],q[h])<v[i].a*down(q[h+1],q[h])) h++;
        dp[i]=dp[q[h]]+v[i].a*v[q[h]+1].b;
        while(h<t && up(q[t],q[t-1])*down(i,q[t])>=up(i,q[t])*down(q[t],q[t-1])) t--;
        q[++t]=i;
    }
    printf("%lld\n",dp[m]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值