Land Acquisition G
绝大部分题解都是用的斜率优化,至少第一页都用的是,剩下的懒得翻了。但我并不想使用斜率优化,哎就是玩……
那能用什么,似乎只剩决策单调性优化了。首先考虑它是否可以使用决策单调性优化,也就是说它的转移方程满不满足那个奇怪的不等式。
和其它题解一样,去除掉无用土地之后,假设我们剩下的这些土地满足每一块土地都比前一块长,却比前一块窄的性质(换句话说,假如用 a 数组代表长度, b 数组代表宽度则是:前者单调递减,后者单调递增)。可以写出方程:
\[f_x=\min\limits_{i=0}^{x-1}{f_i+a_{i+1}\times b_x}
\]
而上述式子是符合那个奇怪不等式的,原因且听我分析一波,当然你跳过也行。由方程可以发现:
\[w[i,j]=a_{i+1}\times b_j
\]
那么:
\[w[i,j+1]=a_{i+1}\times b_{j+1}
\]
\[w[i,j+1]-w[i,j]=a_{i+1}\times(b_{j+1}-b_j)
\]
同理:
\[w[i+1,j+1]-w[i+1,j]=a_{i+2}\times(b_{j+1}-b_j)
\]
所以:
\[w[i+1,j+1]-w[i+1,j]-(w[i,j+1]-w[i,j])=(a_{i+2}-a_{i+1})\times (b_{j+1}-b_j)
\]
由于 a 数组单增,所以第一个乘数是正的;因为 b 数组单减,所以第二个乘数是负的。综上,这个减法的结果是负的。所以有:
\[w[i+1,j+1]-w[i+1,j]-w[i,j+1]+w[i,j]<0
\]
\[w[i+1,j+1]+w[i,j]<w[i+1,j]+w[i,j+1]
\]
我们开心地发现上述式子就是那个可爱的不等式。得到这个之后我们就可以使用决策单调性来优化啦!
代码和AC记录:
#include<cstdio>
#include<algorithm>
#define zczc
#define int long long
using namespace std;
const int N=50010;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
inline void swap(int &s1,int &s2){int s3=s1;s1=s2;s2=s3;return;}
inline int max(int s1,int s2){return s1<s2?s2:s1;}
int m;
struct node{int a,b;}a[N];
inline bool cmp(node s1,node s2){return s1.a==s2.a?s1.b>s2.b:s1.a>s2.a;}
bool operator <(node s1,node s2){return s1.a<=s2.a&&s1.b<=s2.b;}
struct no{int id,l;}st[N];
int top,f[N];
int cost(int x,int y){return f[x]+a[y].a*a[x+1].b;}
int workf(int x){
int l=1,r=top,mid;
while(l<r)st[mid=l+r+1>>1].l<=x?l=mid:r=mid-1;
return st[l].id;
}
signed main(){
#ifdef zczc
freopen("in.txt","r",stdin);
#endif
read(m);
for(int i=1;i<=m;i++){read(a[i].a);read(a[i].b);}
sort(a+1,a+m+1,cmp);int h=0;
for(int i=1;i<=m;i++){if(i&&a[i]<a[h])continue;a[++h]=a[i];}
m=h;for(int i=1;i<=m;i++)swap(a[i].a,a[i].b);
st[++top]=(no){0,1};
for(int i=1;i<=m;i++){
f[i]=cost(workf(i),i);
while(top&&cost(st[top].id,st[top].l)>=cost(i,st[top].l))top--;
if(top==0){st[++top]=(no){i,i+1};continue;}
int l=max(i+1,st[top].l),r=m,mid;
while(l<r)cost(st[top].id,mid=l+r>>1)>=cost(i,mid)?r=mid:l=mid+1;
if(cost(st[top].id,l)>=cost(i,l))st[++top]=(no){i,l};
}
printf("%lld\n",f[m]);
return 0;
}
一如既往,万事胜意