标签:代码 tps lap pac 操作 algorithm cpp can color
双倍经验(美滋滋~~):
回归正题:
本蒟蒻用的方法:动态规划$+$斜率优化$+$单调队列
其实这种斜率优化的题目大都差不多吧,这里主要讲本题的突破口:
对于每两块土地$x,y$来说,当$l[x]>l[y]$并且$h[x]>h[y]$时,我们可以得到第$y$块土地是没有价值的,因为如果把这两块土地一起购买的话,最长的长选$x$的,而最长的宽也选$x$的
所以我们想到把每块土地按照长度从小到大排序,长度相同按照宽度从小到大排序,把类似上面$y$这种土地的丢弃后(可以用栈来操作),我们会发现一个有趣的现象:
在最优决策下,我们分组分成的土地都会是上面最后的栈内连续的一段,举个例子:
当$l[x]>l[y]>l[z]$并且$h[x]<h[y]<h[z]$时,如果我们不选连续的一段分为一组,即:把$x,z$分为一组,$y$分为一组,那么费用为$l[x]*h[z]+l[y]*h[y]$
而如果我们把这三个连续的分成一组呢?费用就是$l[x]*h[z]$,很明显$y$的费用省去了
考虑$dp$:
设$f[i]$表示前$i$个土地的最小花费
很容易想出$dp$方程:$$f[i]=min(f[i],f[j]+h[j+1]*l[i])$$
然而这时朴素$n^2$的,考虑优化,看到乘法就想到斜率优化了吧。。。。
弄个单调队列维护一下收工咯
代码:
#include<cstdio> #include<cstring> #include<algorithm> #define N 210007 #define ll long long using namespace std; struct node { ll x,y; }val1[N],val2[N]; ll n; ll list[N],f[N]; bool cmp(node n1,node n2) { if(n1.x>n2.x) return 0; if(n1.x<n2.x) return 1; if(n1.y>n2.y) return 0; if(n1.y<n2.y) return 1; return 1; } double Get_k(int x,int y) { return double(f[y]-f[x])/double(val2[x+1].y-val2[y+1].y); } signed main() { scanf("%lld",&n); for(int i=1;i<=n;++i) scanf("%lld%lld",&val1[i].x,&val1[i].y); sort(val1+1,val1+n+1,cmp); int p=1; val2[1]=val1[1]; for(int i=2;i<=n;++i) { while(p>0&&val2[p].y<=val1[i].y) --p; val2[++p]=val1[i]; } int head=1,tail=1;list[1]=0; for(int i=1;i<=p;++i) { while(head<tail&&Get_k(list[head],list[head+1])<val2[i].x) ++head; f[i]=f[list[head]]+val2[list[head]+1].y*val2[i].x; while(head<tail&&Get_k(list[tail-1],list[tail])>Get_k(list[tail],i)) --tail; list[++tail]=i; } printf("%lld",f[p]); }
[USACO08MAR]土地征用Land Acquisition
标签:代码 tps lap pac 操作 algorithm cpp can color
原文地址:https://www.cnblogs.com/yexinqwq/p/10263703.html