zoukankan      html  css  js  c++  java
  • [atARC070E]NarrowRectangles

    记$len_{i}=r_{i}-l_{i}$,即第$i$个区间的长度

    用$f_{i,j}$表示前$i$个区间合法,第$i$个区间位于$[j,j+len_{i}]$的最小代价,暴力dp的时间复杂度为$o(nL^{2})$

    考虑$f_{i,j}$的转移,即$f_{i,j}=min_{[j,j+len_{i}]cap[k,k+len_{i-1}] e empty}f_{i-1,k}+|j-l_{i}|$

    不难证明,这样的$k$是一段连续区间,可以表示为$[j-x,j+y]$($x,yge 0$)

    接下来,对每一个$i$,若将$f_{i,j}$看成关于$j$的函数且用直线连结相邻点,那么可以证明其具有凸性

    考虑归纳,更严谨的描述是:令$f'_{i,j}=f_{i,j}-f_{i,j+1}$,证明$f'_{i,j}$单调不递增

    记$[x_{0},y_{0})$为$f'_{i,j}=0$的区间($[x,y]$就是$f_{i,j}$最小值的区间),根据凸性来考虑其最小值的位置——

    1.$jin [x_{0}-y,y_{0}+x]$,最小值位于$f_{i-1,x_{0}}$(即原来最小值)

    2.$j<x_{0}-y$,最小值位于$f_{i-1,j-x}$

    3.$j>y_{0}+x$,最小值位于$f_{i-1,j+y}$

    可以发现,这等价于将$(-infty,x_{0}]$向左移动$y$格,将$[y_{0},infty)$向右移动$x$格,空出来的部分仍然取最小值

    这是有凸性的,再加上一个绝对值函数,显然仍然具有凸性,因此即证明了该结论

    考虑这件事情如何维护,记$a_{k}$为第小的$j$满足$f'_{i,j}ge k$的$j$(特别的,$a_{i}=-infty$),将$a[0,i)$与$a[-i,0)$分别用一个set维护,分别考虑移动和加入绝对值:

    (不难发现$x_{0}=a_{0}$,$y_{0}=a_{-1}$)

    1.移动是比较容易的,分别记录一个懒标记即可

    2.考虑加入一个$|j-l_{i}|$,将其与$[x_{0},y_{0}]$分类讨论:

    (1)$l_{i}in [x_{0},y_{0})$,相当于将$a[0,i)$右移一位,之后加入$f'_{i,l_{i}}=-1$,即$a_{0}=a_{-1}=l_{i}$(其余位置由于用set维护,不需要实际去移动它);

    (2)$l_{i}<x_{0}$,相当于将两个$l_{i}$(由于左加1自身减1会导致一个值不存在,也加到$l_{i}$上)加入左边的集合,并将$a_{0}$移动到右边

    (3)$l_{i}>y_{0}$,类似的,即将两个$l_{i}$加入右边,并将$a_{-1}$移动到左边

    关于最后的答案,不断维护最小值上的值即可

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 100005
     4 #define ll long long
     5 multiset<ll>vl,vr;
     6 int n,l[N],r[N];
     7 ll tagl,tagr,ans;
     8 int main(){
     9     scanf("%d",&n);
    10     for(int i=1;i<=n;i++)scanf("%d%d",&l[i],&r[i]);
    11     vl.insert(l[1]);
    12     vr.insert(l[1]);
    13     for(int i=2;i<=n;i++){
    14         int x=r[i-1]-l[i-1],y=r[i]-l[i];
    15         tagl-=y;
    16         tagr+=x;
    17         ll x0=(*--vl.end())+tagl,y0=(*vr.begin())+tagr;
    18         if ((x0<=l[i])&&(l[i]<y0)){
    19             vl.insert(l[i]-tagl);
    20             vr.insert(l[i]-tagr);
    21         }
    22         else{
    23             if (l[i]<x0){
    24                 ans+=x0-l[i];
    25                 vl.insert(l[i]-tagl);
    26                 vl.insert(l[i]-tagl);
    27                 vl.erase(--vl.end());
    28                 vr.insert(x0-tagr);
    29             }
    30             else{
    31                 ans+=l[i]-y0;
    32                 vr.insert(l[i]-tagr);
    33                 vr.insert(l[i]-tagr);
    34                 vr.erase(vr.begin());
    35                 vl.insert(y0-tagl);
    36             }
    37         }
    38     }
    39     printf("%lld",ans);
    40 }
    View Code
  • 相关阅读:
    Ubuntu安装Cassandra
    Ubuntu安装中文输入法
    CoreOS, Kubernetes, etcd
    CountDownLatch, CyclicBarrier and Semaphore
    Java Primitives and Bits
    vue 和 webstorm(01) 之 基本入门 _fei
    ubuntu 命令窗口背景颜色 #300a24 _fei
    2345 看图王ad介绍----关闭广告 _fei
    PHP 使用 pdo 操作oracle数据库 报错 _fei
    PHP 使用 pdo 操作oracle数据库 报错 _fei
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14356261.html
Copyright © 2011-2022 走看看