[BZOJ] 1597: [Usaco2008 Mar]土地购买
记一次\(O(nlogn)\)吊锤\(O(n)\)实录
设\(f[i]\)表示前\(i\)块土地,第\(i\)块必选的最小代价
为了方便转移,按\(h\)为第一关键字递减,\(w\)为第二关键字递增排序,就有
\[f[i]=\min_{j=1}^{i-1}\{f[j]+cost[j+1][i]\}
\]
其中
\[cost[i][j]=h[i]*\max_{k=i}^j\{w[k]\}
\]
状态是\(O(n)\)的,转移可以用ST表优化到\(O(n)\)
这时候我们就得到了一个\(O(n^2)\)的优秀TLE解法
实际上这里不需要ST表,对于一块土地,如果有另一块土地,比它长,还比它宽,那它就可以在买那个土地时顺便买走
所以,最终的土地序列是\(h\)递减,\(w\)递增的
因此可以改写一下DP式
\[f[i]=\min_{j=1}^{i-1}\{f[j]+h[j+1]\times w[i]\}
\]
设\(cost[i][j]=w[i]\times h[j+1]\)
\[\begin{align}
cost[i][j]+cost[i+1][j+1]=w[i]\times h[j+1]+w[i+1]\times h[j+2]\\
cost[i+1][j]+cost[i][j+1]=w[i+1]\times h[j+1]+w[i]\times h[j+2]
\end{align}
\]
(1)式减(2)式得
\[LHS=cost[i][j]+cost[i+1][j+1]-cost[i+1][j]-cost[i][j+1]
\]
\[\begin{align*}
RHS&=w[i]\times (h[j+1]-h[j+2])+w[i+1]\times(h[j+2]-h[j+1])\\
&=(h[j+1]-h[j+2])\times (w[i]-w[i+1])
\end{align*}
\]
由于h递减,w递增
\[\begin{align*}
h[j+1]-h[j+2]>0\\
w[i]-w[i+1]<0
\end{align*}
\]
因此
\[RHS<0
\]
所以
\[cost[i][j]+cost[i+1][j+1]<cost[i][j+1]+cost[i+1][j]
\]
至此,我们严格证明了\(cost\)是一个凸函数,所以该DP式满足决策单调性
我们可以用单调队列维护,复杂度\(O(nlogn)\)
(不知道为什么甚至用了deque,跑得比大部分\(O(n)\)的斜率优化还快)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<bitset>
#include<deque>
using namespace std;
inline int rd(){
int ret=0,f=1;char c;
while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
while(isdigit(c))ret=ret*10+c-'0',c=getchar();
return ret*f;
}
const int MAXN = 50005;
inline void upmax(int &x,int y){x=max(x,y);}
inline void upmin(int &x,int y){x=min(x,y);}
int n;
typedef long long ll;
struct Node{
int x,y;
bool operator <(const Node &rhs)const{
return x==rhs.x?y>rhs.y:x>rhs.x;
}
}tmp[MAXN],node[MAXN];
int tot;
struct Que{
int l,r,p;
Que(int _p,int _l,int _r){l=_l;r=_r;p=_p;}
};
deque<Que> Q;
ll f[MAXN];
ll calc(int p,int x){
return f[p]+1ll*node[p+1].x*node[x].y;
}
int fnd(int x){
int l=Q.back().l,r=Q.back().r,p=Q.back().p,ret;
while(l<r){
int mid=(l+r)>>1;
if(calc(x,mid)<=calc(p,mid))r=mid;
else ret=mid,l=mid+1;
}
return ret+1;
}
signed main(){
memset(f,0x7f,sizeof(f));
f[0]=0;
n=rd();
for(int i=1;i<=n;i++)tmp[i].x=rd(),tmp[i].y=rd();
sort(tmp+1,tmp+1+n);
for(int i=1;i<=n;i++){
if(tot&&node[tot].y>=tmp[i].y)continue;
node[++tot]=tmp[i];
}
Q.push_back(Que(0,1,tot));
for(int i=1;i<=tot;i++){
while(!Q.empty()&&Q.front().r<i)Q.pop_front();
f[i]=calc(Q.front().p,i);//f[i]=f[p]+cost[p+1][i]
if(calc(i,tot)>calc(Q.back().p,tot))continue;
while(!Q.empty()&&calc(i,Q.back().l)<calc(Q.back().p,Q.back().l))Q.pop_back();
if(Q.empty()){Q.push_back(Que(i,i+1,tot));continue;}
int pos=fnd(i);
Q.back().r=pos-1;Q.push_back(Que(i,pos,tot));
}
cout<<f[tot];
return 0;
}
本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9811193.html