D - Equal Cut

题意:将长为n的序列分成连续的4个非空区间,求出每个区间的和,使得max(区间和)-min(区间和) 最小

思路:割3刀,很自然想到枚举第二刀i,正常做法O(n^3),注定要凉。 我们将区间[1,i-1]划分成2个非空区间L1,L2,为了划分后,使得有:最大值尽可能小,最小值尽可能大,则有L1和L2的差距越小越好。并且有i+1划分时,只需要把i的L1继续使用。对于划分区间[i+1,n]同理

#include<bits/stdc++.h>
#define PI acos(-1.0)
#define pb push_back
#define F first
#define S second
using namespace std;
typedef long long ll;
const int N=2e5+5;
const int MOD=1e9+7;
ll a[N];
ll sum[N];
//ll ans[N];

ll gao(int l,int r){  //求区间l,r的和
    return sum[r]-sum[l-1];
}

int main(void){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);

    int n ;
    cin >>n;
    for(int i=1;i<=n;i++)   cin >> a[i];
    for(int i=1;i<=n;i++)   sum[i]=sum[i-1]+a[i]; //求前缀和
    ll l=1,r=3;
    ll ans=1e18+8;
    for(int i=2;i<=n-2;i++){
         while(l+1<i&&abs(gao(1,l)-gao(l+1,i))>=abs(gao(1,l+1)-gao(l+2,i)))//若[1,l+1]和[l+1,i]的距离比[1,l+1]和[l+2,i]的距离小,那么我们就继续加,使得两边尽可能平衡
            l++;
         while(r+1<n&&abs(gao(i+1,r)-gao(r+1,n))>=abs(gao(i+1,r+1)-gao(r+2,n)))
            r++;
         set<ll>st;///利用set的log排序
         st.insert(gao(1,l));
         st.insert(gao(l+1,i));
         st.insert(gao(i+1,r));
         st.insert(gao(r+1,n));
         ans=min(ans,abs(*st.begin()-*prev(st.end())));
    }
    cout << ans << endl;

    return 0;
}