Two Buildings(决策单调性+分治)

在这里插入图片描述
题目大意:
给定一个长度为 n n n 的数组 h h h 求:
m a x (   ( h i + h j ) ( j − i )   ) max(\ (h_i+h_j)(j-i)\ ) max( (hi+hj)(ji) )
题目分析:
此题可转化为求:
m a x (   ( h j − ( − h i ) ) ( j − i )   ) max(\ (h_j-(-h_i))(j-i)\ ) max( (hj(hi))(ji) )
这个就相当于在二维坐标系中求最大矩形的面积,我们设 a , b a,b a,b 数组分别为矩形的左下角和右上角那两个坐标的纵坐标(其横坐标就是其数组下标),则题目所求即为:
m a x (   ( b j − a i ) ( j − i )   ) max(\ (b_j-a_i)(j-i)\ ) max( (bjai)(ji) )
将上式和题目所求联立可得 a i = − h i , b i = h i a_i=-h_i,b_i=h_i ai=hi,bi=hi ,这样我们就可以得到 a , b a,b a,b 数组了
我们继续考虑如何求 m a x (   ( b j − a i ) ( j − i )   ) max(\ (b_j-a_i)(j-i)\ ) max( (bjai)(ji) )
我们发现对于一个给定 a i a_i ai 在选择 b j b_j bj 与之配对时 b j b_j bj 是有决策单调性的:越往右上越优,即对于下面两个决策:
b i ≤ b j ( i < j ) b_i\le b_j(i<j) bibj(i<j)
决策 b j b_j bj 显然优于决策 b i b_i bi 所以可以直接将 b i b_i bi 状态删掉,对 a a a 数组同理(如果不理解在纸上画一画图可能就明白了)
接下来我们考虑如何快速处理出答案:
a , b a,b a,b 数组分别有 n , m n,m n,m 个元素(已按从左下到右上排好序), a . x a.x a.x 表示原数组下标即二维平面的横坐标, a . y a.y a.y 表示二维平面的那个纵坐标, b b b 数组同理
s o l v e ( l 1 , r 1 , l 2 , r 2 ) solve(l1,r1,l2,r2) solve(l1,r1,l2,r2) 表示 a a a 数组下标从 l 1 l1 l1 r 1 r1 r1 b b b 数组从 l 2 l2 l2 r 2 r2 r2 的最优解,我们采用一下过程进行分治:
m i d = l 1 + r 1 2 mid=\frac{l1+r1}2 mid=2l1+r1 我们扫描 b b b 数组并记录对 a m i d a_{mid} amid 的最优解的下标 p o s pos pos ,然后答案就是 a m i d , b p o s a_{mid},b_{pos} amid,bpos 构成的矩形, s o l v e ( l 1 , m i d − 1 , l 2 , p o s ) solve(l1,mid-1,l2,pos) solve(l1,mid1,l2,pos) s o v l e ( m i d + 1 , r 1 , p o s , r 2 ) sovle(mid+1,r1,pos,r2) sovle(mid+1,r1,pos,r2) 三者的最大值(因为决策是具有单调性的)

具体细节见代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<stack>
#define ll long long
#define inf 0x3f3f3f3f
#define Inf 0x3f3f3f3f3f3f3f3f
using namespace std;
ll read()
{
	ll res = 0,flag = 1;
	char ch = getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch == '-') flag = -1;
		ch = getchar();
	}
	while(ch>='0' && ch<='9')
	{
		res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
		ch = getchar();
	}
	return res*flag;
}
const int maxn = 5e6+5;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
struct node{
	ll x,y;
	bool operator < (const node b) const {
		if(x == b.x) return y < b.y;
		return x < b.x;
	}
}a[maxn],b[maxn];
ll n,m,h[maxn];
bool vis[maxn];
void init_a()
{
	memset(vis,0,sizeof(vis));
	sort(a+1,a+n+1);
	int last = 1,cnt = 0;
	for(int i = 2;i <= n;i++)
		if(a[i].y >= a[last].y) vis[i] = true;
		else last = i;
	for(int i = 1;i <= n;i++)
		if(!vis[i]) a[++cnt] = a[i];
	n = cnt;
}
void init_b()
{
	memset(vis,0,sizeof(vis));
	sort(b+1,b+m+1);
	int last = m,cnt = 0;
	for(int i = m-1;i;i--)
		if(b[i].y <= b[last].y) vis[i] = true;
		else last = i;
	for(int i = 1;i <= m;i++)
		if(!vis[i]) b[++cnt] = b[i];
	m = cnt;
}
ll calc(ll i,ll j)
{
	if(a[i].x>b[j].x && a[i].y > b[j].y)
		return -Inf;
	return (b[j].x-a[i].x)*(b[j].y-a[i].y);
}
ll solve(ll l1,ll r1,ll l2,ll r2)
{
	if(l1>r1 || l2>r2) return 0;
	int mid = l1+r1>>1;
	int pos = l2;
	for(int i = l2+1;i <= r2;i++)
		if(calc(mid,pos) < calc(mid,i))
			pos = i;
	return max({calc(mid,pos),solve(l1,mid-1,l2,pos),solve(mid+1,r1,pos,r2)});
}
int main()
{
	n = read();m = n;
	for(int i = 1;i <= n;i++)
	{
		h[i] = read();
		a[i].x = b[i].x = i;
		a[i].y = -h[i];
		b[i].y = h[i];
	}
	init_a();
	init_b();
	printf("%lld\n",solve(1,n,1,m));
	return 0;
}
  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值