gym102920L Two Buildings (2020-2021 ACM-ICPC, Asia Seoul Regional Contest)决策单调性

题意

给定数组(h),求(max_{1le i<jle n}(h[i]+h[j])*(j-i))(1le n,h[i]le 1e6)

分析

  1. 把原式改写为(max_{1le i<jle n}(h[i]-(-h[j]))*(j-i)),则对于每个平面点((i,h[i])),找到它右下角的点((j,-h[j]))使得面积最大。

  2. 对于(i_1<i_2),若(h[i_1]ge h[i_2]),则取(i_2)的地方取(i_1)一定更大,所以可以只取(i)从左至右升序排列的点。同理,对于(j_1<j_2),若(-h[j_1]ge -h[j_2]),则取(j_1)的地方取(j_2)一定更大,所以可以只取(j)从右至左降序排列的点。

  3. 对于点(i),若取(j)时取得最大值,则对于点(l<i),在([1-j])取得最大值;则对于点(r>i),在([j-n])取得最大值。所以可以利用决策单调性进行分治。

    1. 对于图中(l<i)的点来说,因为(j)(k)优,所以(S_1ge S_2),得到(S_1+S3gt S_2-S_4)。则对于(l)来说,在(j)左侧取得最大值。同理可得点(r>i),在([j-n])取得最大值。
      决策单调性

代码

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int maxn=1e6+5;
ll h[maxn],a[maxn],b[maxn],ai[maxn],bi[maxn],ans;

void proc(int l,int r,int L,int R)
{
    ll Ans=0,id=L,mid=(l+r)/2;
    for(ll i=L;i<=R;i++)
    {
        ll tmp=(a[mid]-b[i])*(bi[i]-ai[mid]);
        if(tmp>Ans)
        {
            Ans=tmp;
            id=i;
        }
    }
    ans=max(ans,Ans);
    if(l<mid)
        proc(l,mid-1,L,id);
    if(mid<r)
        proc(mid+1,r,id,R);
}

void solve(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>h[i];
        a[i]=h[i];
        b[i]=-h[i];
    }
    int cnt=1,R=n;
    ai[1]=1;
    bi[n]=n;
    for(int i=2;i<=n;i++)
    {
        if(a[i]>a[cnt])
        {
            a[++cnt]=a[i];
            ai[cnt]=i;
        }
    }
    for(int i=n-1;i>=1;i--)
    {
        if(b[i]<b[R])
        {
            b[--R]=b[i];
            bi[R]=i;
        }
    }
    ans=0;
    proc(1,cnt,R,n);
    cout<<ans<<'
';
}

int main()
{
    ios::sync_with_stdio(false);
    int t=1;
    // cin>>t;
    while(t--)
        solve();

    return 0;
}

参考链接

  1. https://www.wjyyy.top/3870.html
原文地址:https://www.cnblogs.com/intmian/p/14588111.html