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;
}