BZOJ 1597 浅谈构造斜率--优化动态规划转移

BZOJ 1597 浅谈构造斜率--优化动态规划转移_第1张图片
世界真的很大
上午考试考得心累
第一题LCA写挂,第三题输出少了个感叹号???“!”
然后想下午趁头脑清晰做一道DP,然后一个班小时就这么过去了
今天运气真的是。。

复习一波斜率优化,原来学过但是感觉忘得差不多了
老老实实把方程写在纸上,一步一步写,不然真的要把自己搞蒙

看题先:

description:

农夫John准备扩大他的农场,他正在考虑N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000). 每块土地的价格是它的面积,但FJ可以同时购买多快土地. 这些土地的价格是它们最大的长乘以它们最大的宽, 但是土地的长宽不能交换. 如果FJ买一块3x5的地和一块5x3的地,则他需要付5x5=25. FJ希望买下所有的土地,但是他发现分组来买这些土地可以节省经费. 他需要你帮助他找到最小的经费.

input:

  • 第1行: 一个数: N
  • 第2..N+1行: 第i+1行包含两个数,分别为第i块土地的长和宽

output:

  • 第一行: 最小的可行费用.

拿到这道题,感觉是DP,因为还要求分段什么的
很自然想到f[i]表示前i个土地,分成“管他多少”段并且i为最后一段末尾的最优值
那么问题就在于,土地并不是序列一样的东西,不存在”前i个土地“什么的,不能把其给出的土地顺序直接就来DP,因为这样等于分的某一段的一定是给出的顺序的连续的某一段,想想就觉得不可能

然后想一想,某一段土地的权值,是其最大的横坐标,和最大的纵坐标之积,那么在一段里面,单论横坐标应该是连续的一段,为了使得每一个x坐标覆盖的范围尽量多。
然后得出结论,这个”序列“应该和x序有一定关系,然后就把样例按x排了个序,所有矩形的左下角靠着原点
画出来,发现一个神奇的东西,”在x单调上升的同时,y单调下降“
当时就一阵蒙蔽,这难道是必然的吗
马上画了个反例。。
但是一旦出现反例,发现这个反例的矩形的x和y都被另一个更大的矩形包括,这就使得一旦选了这个更大的矩形,小矩形就完全不用考虑了,随便放进去就行

然后就把这样的矩形删掉,赫然发现:”在x单调上升的同时,y单调下降“,这就变成了一个必然的规律了

这样”序列“就出来了,我们分的所有段,必然是这些矩形里面连续的一段
然后就可以一下子写出DP方程:
f[i]=min(f[j]+a[j+1].y * a[i].x)
但是这样是n^2的,所以考虑优化
方程转移时填表法,一开始想能不能什么数据结构,但是由于右边有一个a[i].x,所以没办法用什么数据结构维护起来,因为每次选最值的条件都不一样

在这样的情况下,且与i(当前枚举项)相关的项同时出现在了方程两边,很自然,斜率优化。
设j,k,设j作为转移项比k更优,那么:
f[j]+a[j+1].y * a[i].x < f[k]+a[k+1] .y * a[i].x
然后由于i与j和k无关,所以把i挪到一边,得:
(f[j]-f[k]) / (a[k+1] .y * a[i].x - a[j+1].y * a[i].x)

#include
#include
#include
using namespace std;
typedef long long dnt;

struct land
{
    dnt x,y;
}lnd[500010],a[500010];

int n,tot=0,q[2000010],h,t;
dnt f[500010];

bool cmp(const land &a,const land &b)
{
    if(a.x==b.x) return a.yy;
    return a.xx;
}

bool check_h(int i)
{
    return f[q[h+1]]-f[q[h]] < (a[q[h]+1].y-a[q[h+1]+1].y) * a[i].x;
}

bool check_t(int i)
{
    return (f[q[t]]-f[q[t-1]])*(a[q[t]+1].y-a[i+1].y) > (f[i]-f[q[t]])*(a[q[t-1]+1].y-a[q[t]+1].y);
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        cin >> lnd[i].x >> lnd[i].y;
    sort(lnd+1,lnd+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
        while(tot && lnd[i].y>=a[tot].y) tot--;
        a[++tot]=lnd[i];
    }
    h=1,t=1,q[1]=0;
    for(int i=1;i<=tot;i++)
    {
        while(hq[h]]+a[q[h]+1].y*a[i].x;
        while(hq[++t]=i;

    }
    cout << f[tot] << endl;
    return 0;
}
/*
EL PSY CONGROO
*/

嗯,就是这样

你可能感兴趣的:(BZOJ,DP,斜率优化)