LGBT学分块

LGBT学分块

fk


题目

【题目描述】

LGTB最近在学分块,但是他太菜了,分的块数量太多他就混乱了,所以只能分成3块

今天他得到了一个数组,他突然也想把它分块,他想知道,把这个数组分成3块,块可以为空,使得3块分块的中的最大值最小
请输出分完之后3块中和的最大值

【输入输出格式】

输入格式:
输入第一行包含一个整数n 代表数组大小
接下来n 个整数\(a_1, a_2, ..., a_n\),代表数组
对于40% 的数据,\(1=<n<= 10\)
对于70% 的数据,\(1=<n<=10^3\)
对于100% 的数据,\(1=<n<=10^5, 1=<a_i<=10^7\)

输出格式:
输出包含1 个整数,代表分块完成后3 块中的最大值

【输入输出样例】

输入样例#1:

5
9 9 8 7 6

输出样例#1:

17

思路

题目大意:
把一个数组分成三部分(每一部分可空),使得三个部分和的最大值最小,输出这个最小的最大值。(有点绕...仔细理解一下)

大致思路
枚举第一个断点,二分确定第二个断点,让后两个块尽量接近,这样就可以保证两个之中的较大者尽量不会超过第一个块。二分出来后,答案会在那个断点的左右(保险)。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
#define FILE freopen("divide.in","r",stdin);freopen("divide.out","w",stdout);
using namespace std;
const int maxn=100000+5;
LL n,a[maxn],sum[maxn]= {0};
LL ans=0x7f7f7f7f7f7f7f;
inline LL ErFen(LL left,LL right,LL i) {
    while(left+1<right) {
        LL mid=(left+right)>>1;
        if(sum[mid]-sum[i]>sum[n]-sum[mid])
            right=mid;
        else
            left=mid;
    }
    return left;
}
int main() {
    ios::sync_with_stdio(false);
//    FILE;
    cin>>n;
    for(LL i=1; i<=n; i++) {
        cin>>a[i];
        sum[i]=sum[i-1]+a[i];
    }
    if(n==1) {
        cout<<sum[1]<<endl;
        return 0;
    }
    if(n==2) {
        cout<<max(sum[1],sum[2])<<endl;
        return 0;
    }

    for(LL i=0; i<n; i++) {
        LL final=ErFen(i+1,n,i);
        ans=min(ans,max(sum[i]-sum[0],
                        max(sum[final]-sum[i],
                            sum[n]-sum[final])));
        ans=min(ans,max(sum[i]-sum[0],
                        max(sum[final+1]-sum[i],
                            sum[n]-sum[final+1])));
    }
    cout<<ans;
    return 0;
}

posted @ 2017-08-22 21:35  YQAccelerator  阅读(126)  评论(0编辑  收藏  举报