• BZOJ 4951 [WF2017]Money for Nothing (决策单调优化DP+分治)


    题目大意:略 题目传送门

    不愧是$World final$的神题,代码短,思维强度大,细节多到吐..调了足足2h

    贪心

    我们利用贪心的思想,发现有一些工厂/公司是非常黑心的

    以工厂为例,对于一个工厂$i$,如果存在一个工厂$j$,$d_{j}<d_{i},p_{j}<p_{i}$,即出货比i早,而且比i便宜

    那么不论我们选择任何消费公司,都一定会选$j$而不是选$i$

    消费公司也用类似的贪心方法,消去那些黑心公司

    以$d$为$x$轴,$p$为$y$轴,我们得到了许多在二维平面上的点,保证$d_{i}$递增,$p_{i}$递减

    这一步贪心可以用单调栈实现

    决策单调性

    发现我们筛出来这些点以后,并没有什么卵用

    假如把这个问题看成一个几何问题,题目转化为,能作为右上角的点视为白点,能作为左下角的点视为黑点,给定很多黑点白点,求白点作为右上角,黑点作为左下角,围成的矩形的面积最大值,且点集内的保证$d_{j}<d_{i},p_{j}<p_{i}$

    以下讨论中,点的编号随横坐标$d$增大而增大

    大胆地猜测一下,假设我们选择一个左下角黑点$i$,它对应的最优右上角白点是$j$,那么当$j-1$不能和$i$构成最优解时,点$i+1$能否和$j-1$构成最优解呢?

    答案是不能,下面给出证明

    我们已知$(x_{j}-x_{i})(y_{j}-y_{i})>(x_{j-1}-x_{i})(y_{j-1}-y_{i}),x_{i}<x_{i+1},y_{i}>y_{i+1},x_{j}<x_{j+1},y_{j}>y_{j+1}$

    假如能构成最优解,那么$(x_{j-1}-x_{i+1})(y_{j-1}-y_{i+1})>(x_{j}-x_{i+1})(y_{j}-y_{i+1})$

    把两式展开,消项可得

    $x_{j}cdot y_{j}-x_{i}cdot y_{j}-x_{j}cdot y_{i}>x_{j-1}cdot y_{j-1}-x_{i}cdot y_{j-1}-x_{j-1}cdot y_{i}$

    $x_{j-1}cdot y_{j-1}-x_{i+1}cdot y_{j-1}-x_{j-1}cdot y_{i+1}>x_{j}cdot y_{j}-x_{i+1}cdot y_{j}-x_{j}cdot y_{i+1}$

    不等号方向相同,两式相加,消去相同项,可得

    $-x_{i}cdot y_{j}-x_{j}cdot y_{i}-x_{i+1}cdot y_{j-1}-x_{j-1}cdot y_{i+1}>-x_{i}cdot y_{j-1}-x_{j-1}cdot y_{i}-x_{i+1}cdot y_{j}-x_{j}cdot y_{i+1}$

    合并,整理可得

    $(x_{i+1}-x_{i})(y_{j-1}-y_{j})+(y_{i}-y_{i+1})(x_{j}-x_{j-1})<0$

    由于$x_{i}<x_{i+1},y_{i}>y_{i+1},x_{j}<x_{j+1},y_{j}>y_{j+1}$,上述式子一定大于$0$,所以这种情况不存在

    分治求解

    我们刚刚发现了这个优美的性质,接下来该如何利用这个性质求解呢?

    考虑分治,用类似于整体二分的方法,把右上角的点看成询问,左下角的点视为操作(决策)

    当前的询问区间是$[l1,r1]$,决策区间是$[l2,r2]$

    现在选择了询问区间的重点$mid$,遍历$[l2,r2]$找到$mid$的决策$p$

    根据决策单调性,$[l1,mid-1]$的决策一定属于$[l2,p]$,$[mid+1,r1]$的决策一定属于$[p,r2]$

    类似于整体二分的方法,递归即可

    繁多的细节

    你作为中国代表队的一员参加了$ACM$,成功晋级$World Final$,然后你一眼看出了贪心,决策单调性,以及靠谱的分治算法,你抢过队友的键盘开始码这道题

    不过这道题代码实现的细节还挺多的

    首先,分治算法中,$mid$的决策$p$可能有多个,它们中的某几个可能同时作为$[l1,mid-1]$和$[mid+1,r1]$的决策

    所以我们要把所有的决策$p$全都推到两边分治

    但如果$mid$找不到决策怎么办?

    找到最大的可能作为$[l1,mid-1]$和$[mid+1,r1]$的决策区间,继续递归

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define N1 500010
     5 #define ll long long
     6 #define dd double
     7 #define inf 1333333333
     8 using namespace std;
     9 
    10 int gint()
    11 {
    12     int ret=0,fh=1;char c=getchar();
    13     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
    14     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
    15     return ret*fh;
    16 }
    17 
    18 int n,m,nn,mm; int stk[N1],tp; ll ans;
    19 struct node{int x,v;}a[N1],b[N1],tmp[N1];
    20 int cmp1(node s1,node s2){ if(s1.x!=s2.x) return s1.x<s2.x; return s1.v<s2.v; }
    21 int cmp2(node s1,node s2){ if(s1.x!=s2.x) return s1.x<s2.x; return s1.v>s2.v; }
    22 
    23 int de;
    24 void solve(int l1,int r1,int l2,int r2)
    25 {
    26     if(l1>r1||l2>r2) return;
    27     int mid=(l1+r1)>>1,i,S=-1,E=-1; ll ma=-1,tmp;
    28     for(i=l2;i<=r2;i++)
    29     {
    30         tmp=1ll*(b[mid].v-a[i].v)*(b[mid].x-a[i].x);
    31           if(b[mid].x<a[i].x||b[mid].v<a[i].v) tmp=-inf;
    32         if(tmp>ma) ma=tmp,S=E=i;
    33         else if(tmp==ma) E=i;
    34     }
    35     if(S==-1&&E==-1) 
    36     {
    37         de=1;
    38         if(l1<=mid+1&&mid+1<=r1)
    39             for(i=l2;i<=r2;i++) if(b[mid+1].v>=a[i].v){ 
    40                 solve(mid+1,r1,i,r2); break; } 
    41         if(l1<=mid-1&&mid-1<=r1)
    42             for(i=r2;i>=l2;i--) if(b[mid-1].x>=a[i].x){ 
    43                 solve(l1,mid-1,l2,i); break; } 
    44           return;
    45     }
    46     ans=max(ans,ma);
    47     solve(l1,mid-1,l2,E); solve(mid+1,r1,S,r2);
    48 }
    49 
    50 int main()
    51 {
    52     scanf("%d%d",&m,&n);
    53     int i;
    54     for(i=1;i<=m;i++){ a[i].v=gint(); a[i].x=gint(); }
    55     for(i=1;i<=n;i++){ b[i].v=gint(); b[i].x=gint(); }
    56     
    57     sort(a+1,a+m+1,cmp1); 
    58     for(tp=0,i=m;i;i--)
    59     {
    60         while(tp>=1&&a[i].v<=a[stk[tp]].v) tp--;
    61         stk[++tp]=i;
    62     }
    63     for(i=1;i<=tp;i++) tmp[i]=a[stk[i]];
    64     for(i=1;i<=tp;i++) a[i]=tmp[tp-i+1];
    65     mm=tp;
    66     
    67     sort(b+1,b+n+1,cmp2); 
    68     for(tp=0,i=1;i<=n;i++)
    69     {
    70         while(tp>=1&&b[i].v>=b[stk[tp]].v) tp--;
    71         stk[++tp]=i;
    72     }
    73     for(i=1;i<=tp;i++) tmp[i]=b[stk[i]];
    74     for(i=1;i<=tp;i++) b[i]=tmp[i];
    75     nn=tp;
    76     
    77     solve(1,nn,1,mm);
    78     printf("%lld
    ",ans);
    79     return 0;
    80 }
  • 相关阅读:
    Springboot操作域对象
    Thymeleaf的条件判断和迭代遍历
    Thymeleaf的字符串与变量输出的操作
    window 2003 实现多用户远程登录
    非常漂亮js动态球型云标签特效代码
    Echarts运用
    sass、less和stylus的安装使用和入门实践
    java,js 解unicode
    Java上传下载excel、解析Excel、生成Excel
    小知识点应用
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10257311.html
Copyright © 2020-2023  润新知