Land Acquisition G

link

绝大部分题解都是用的斜率优化,至少第一页都用的是,剩下的懒得翻了。但我并不想使用斜率优化,哎就是玩……

那能用什么,似乎只剩决策单调性优化了。首先考虑它是否可以使用决策单调性优化,也就是说它的转移方程满不满足那个奇怪的不等式。

和其它题解一样,去除掉无用土地之后,假设我们剩下的这些土地满足每一块土地都比前一块长,却比前一块窄的性质(换句话说,假如用 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;
}
posted @ 2022-02-19 17:53  Feyn618  阅读(31)  评论(0编辑  收藏  举报