Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

バームクーヘン(Baumkuchen)

JOI 君は妹のJOI 子ちゃんとJOI 美ちゃんと一緒におやつを食べようとしている．今日のおやつは3 人の大好物のバームクーヘンだ．

バームクーヘンは下図のような円筒形のお菓子である．3 人に分けるために，JOI 君は半径方向に刃を3回入れて，これを3 つのピースに切り分けなければならない．ただしこのバームクーヘンは本物の木材のように固いので，刃を入れるのは簡単ではない．そのためこのバームクーヘンにはあらかじめ $N$ 個の切れ込みが入っており，JOI 君は切れ込みのある位置でのみ切ることができる．切れ込みに1 から $N$ まで時計回りに番号をふったとき，$1 \leq i \leq N - 1$ に対し， $i$ 番目の切れ込みと$i + 1$ 番目の切れ込みの間の部分の大きさは $A_i$ である．また $N$ 番目の切れ込みと1 番目の切れ込みの間の部分の大きさは $A_N$ である．

図1: バームクーヘンの例 $N = 6, A_1 = 1, A_2 = 5, A_3 = 4, A_4 = 5, A_5 = 2, A_6 = 4$

課題

切れ込みの個数 $N$ と，各部分の大きさを表す整数 $A_1,...,A_N$ が与えられる．バームクーヘンを3 つに切り分けたときの，最も小さいピースの大きさの最大値を出力するプログラムを作成せよ．

入力

標準入力から以下のデータを読み込め．

1 行目には，整数 $N$ が書かれている．これはバームクーヘンに $N$ 個の切れ込みがあることを表す．

続く$N$ 行のうちの $i$ 行目$(1 \leq i \leq N)$ には，整数 $A_i$ が書かれている．これは $i$ 番目の切れ込みと $i + 1$ 番目の切れ込みの間の部分 ($i = N$ のときは $N$ 番目の切れ込みと1 番目の切れ込みの間の部分) の大きさが $A_i$ であることを表す．

出力

標準出力に，バームクーヘンを3 つに切り分けたときの，最も小さいピースの大きさの最大値を表す整数を1 行で出力せよ．

制限

すべての入力データは以下の条件を満たす．

$3 \leq N \leq 100000$

$1 \leq A_i \leq 1000000000 (1 \leq i \leq N)$

入出力例

入力例 1

6
1
5
4
5
2
4

出力例 1

6

図2: 1 番目の切れ込みと3 番目の切れ込みと5 番目の切れ込みで切るのが最善である．

入力例 2

30
1
34
44
13
30
1
9
3
7
7
20
12
2
44
6
9
44
31
17
20
33
18
48
23
19
31
24
50
43
15

出力例 2

213

問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in C++11 (judge verdict: Accepted)

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define each(itr,c) for(__typeof(c.begin()) itr=c.begin(); itr!=c.end(); ++itr)
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define fi first
#define se second

int main()
{
    int n;
    scanf(" %d", &n);

    ll sum=0;
    vector<ll> a(2*n);
    rep(i,n)
    {
        scanf(" %lld", &a[i]);
        a[i+n]=a[i];
        sum+=a[i];
    }

    vector<ll> presum(2*n+1,0);
    for(int i=1; i<=2*n; ++i) presum[i] = presum[i-1]+a[i-1];

    ll ans=0;
    rep(i,n)
    {
        int x = lower_bound(all(presum),presum[i]+sum/3)-presum.begin();
        int y = lower_bound(all(presum),presum[i]+sum*2/3)-presum.begin();
        for(int j=x-1; j<=x+1; ++j)for(int k=y-1; k<=y+1; ++k)
        {
            if(i<j && j<k && j<i+n && k<i+n)
            {
                ll p = presum[j]-presum[i];
                ll q = presum[k]-presum[j];
                ll r = presum[i+n]-presum[k];

                ans = max(ans, min({p,q,r}));
            }
        }
    }
    printf("%lld\n", ans);
    return 0;
}