题目大意:略 题目传送门
不愧是$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\n",ans); 79 return 0; 80 }
BZOJ 4951 [WF2017]Money for Nothing (决策单调优化DP)
原文:https://www.cnblogs.com/guapisolo/p/10257311.html