zoukankan      html  css  js  c++  java
  • [Bzoj1597][Usaco2008 Mar]土地购买(斜率优化)

    题目链接

    因为题目说可以分组,并且是求最值,所以斜率优化应该是可以搞的,现在要想怎么排序使得相邻的数在一个组中最优。

    我们按照宽$w$从小到大,高$h$从小到大排序。这时发现可以筛掉一些一定没有贡献的土地,什么样的土地没有贡献呢?这样的:$h[i]<=h[j]& &w[i]<=w[j]$,此时i没有贡献。

    所以排序并筛掉无用的土地后,剩余的土地是按照$w[i]<  w[j]< w[k]& &h[i]> h[j]>h[k]$ $(i<j<k)$

    这时候我们的最优分组一定是选择连续的土地为一组。因为如果i和k一组,j一组,则此时的花费是$h[i]*w[k]+h[j]*w[j]$

    而选择$i,j,k$一组,则花费为$h[i]*w[k]$

    所以此时有$O(n^{2})$的$dp$:

    $dp[i]$为前$i$块土地的最少花费,$dp[i]=max(dp[i],dp[j]+h[j+1]*w[i])$。

    但是复杂度不允许QAQ

    所以推式子:

    设$k<j<i$,且i从j转移比从k转移更优。

    $dp[j]+h[j+1]*w[i]leq dp[k]+h[k+1]*w[i]$

    $dp[j]-dp[k]leq (h[k+1]-h[j+1])*w[i]$

    $ frac{dp[j]-dp[k]}{h[k+1]-h[j+1]}leq w[i]$

    $ frac{dp[j]-dp[k]}{h[j+1]-h[k+1]}geq- w[i]$

    将$(h[j+1],dp[j]),(h[k+1],dp[k])$看成二维平面的点,因为$k<j& &h[k+1]>h[j+1]$,所以点集应该是从左往右。

    维护一个单调队列,如果当前点为$i$,队首为$L$,则如果$L$没有$L+1$到$i$更优,则队首出队。当前最优点为队首。同时还要维护队尾。

     PS:因为以前吃过精度的坑,所以写斜率优化基本是移相相乘。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn = 5e4 + 100;
     5 struct node {
     6     ll w, h;
     7 }a[maxn], b[maxn];
     8 bool cmp(node x, node y) {
     9     return x.w == y.w ? x.h < y.h : x.w < y.w;
    10 }
    11 ll dp[maxn]; int q[maxn];
    12 ll check1(int j, int k) {
    13     return dp[j] - dp[k];
    14 }
    15 ll check2(int j, int k) {
    16     return b[j + 1].h - b[k + 1].h;
    17 }
    18 int main() {
    19     int n, cnt = 0;
    20     scanf("%d", &n);
    21     for (int i = 1; i <= n; i++)
    22         scanf("%lld%lld", &a[i].w, &a[i].h);
    23     sort(a + 1, a + 1 + n, cmp);
    24     for (int i = 1; i <= n; i++) {
    25         while (cnt != 0 && b[cnt].h <= a[i].h)
    26             cnt--;
    27         b[++cnt] = a[i];
    28     }
    29     int l = 0, r = 0;
    30     for (int i = 1; i <= cnt; i++) {
    31         while (l < r && check1(q[l], q[l + 1]) >= -b[i].w * check2(q[l], q[l + 1]))
    32             l++;
    33         dp[i] = dp[q[l]] + b[q[l] + 1].h * b[i].w;
    34         while (l < r && check1(q[r - 1], q[r]) * check2(q[r], i) <= check1(q[r], i) * check2(q[r - 1], q[r]))
    35             r--;
    36         q[++r] = i;
    37     }
    38     printf("%lld
    ", dp[cnt]);
    39 }
  • 相关阅读:
    Android studio导入开源项目
    使用Kindeditor上传图片
    IOS实现自动循环滚动广告--ScrollView的优化和封装
    Android开发之Drag&Drop框架实现拖放手势
    IOS中的手势详解
    Android实现图片轮显效果——自定义ViewPager控件
    IOS欢迎界面Launch Screen动态加载广告
    tomcat 启动参数 Xms, Xmx, XX:MaxNewSize, XX:PermSize, -XX:MaxPermSize, Djava.awt.headless
    PHP提升echo, printf, print, file_put_contents等输出方法的效率
    WIN7下强制分第四个主分区的方法
  • 原文地址:https://www.cnblogs.com/sainsist/p/11563980.html
Copyright © 2011-2022 走看看