ソースコード
#include<bits/stdc++.h>
using namespace std;
const int INF = 1 << 30;
template< typename T >
struct SegmentTree
{
vector< T > seg;
int sz;
SegmentTree(int n)
{
sz = 1;
while(sz < n) sz <<= 1;
seg.assign(2 * sz - 1, INF);
}
T merge(T a, T b)
{
return (min(a, b));
}
void set(int k, int x)
{
seg[k + sz - 1] = x;
}
void build()
{
for(int k = sz - 2; k >= 0; k--) {
seg[k] = merge(seg[2 * k + 1], seg[2 * k + 2]);
}
}
T rmq(int a, int b, int k, int l, int r)
{
if(a >= r || b <= l) return (INF);
if(a <= l && r <= b) return (seg[k]);
return (merge(rmq(a, b, 2 * k + 1, l, (l + r) >> 1),
rmq(a, b, 2 * k + 2, (l + r) >> 1, r)));
}
T rmq(int a, int b)
{
return (rmq(a, b, 0, 0, sz));
}
void update(int k, T x)
{
k += sz - 1;
seg[k] = x;
while(k > 0) {
k = (k - 1) >> 1;
seg[k] = merge(seg[2 * k + 1], seg[2 * k + 2]);
}
}
};
int N, A[3000], B[3000];
int dp[3000][3000];
int sum[3005];
int main()
{
cin >> N;
for(int i = 0; i < N; i++) cin >> A[i];
for(int i = 0; i < N; i++) cin >> B[i];
for(int i = 0; i < N; i++) sum[i + 1] += sum[i] + A[i];
fill_n(*dp, 3000 * 3000, INF);
vector< SegmentTree< int > > latte(N, SegmentTree< int >(N)), malta(N, SegmentTree< int >(N));
// l(low≦l≦k) := dp[j][l-1]+B[l]
// l(j≦l≦low-1) := dp[l+1][k]+B[l]
// ここで k と j は定数なので kとjに関するセグ木があればよくて
auto update = [&](int x, int y)
{
if(y + 1 < N) latte[x].update(y + 1, dp[x][y] + B[y + 1]);
if(x - 1 >= 0) malta[y].update(x - 1, dp[x][y] + B[x - 1]);
};
for(int i = 0; i < N; i++) {
dp[i][i] = B[i];
update(i, i);
}
for(int i = 2; i <= N; i++) {
for(int j = 0; j <= N - i; j++) {
int k = j + i - 1; // [j, k]
// sum1 >= sum2
int low = j, high = k + 1;
while(high - low > 0) {
int mid = (low + high) >> 1;
int sum1 = sum[mid] - sum[j];
int sum2 = sum[k + 1] - sum[mid + 1];
if(sum1 >= sum2) high = mid;
else low = mid + 1;
}
dp[j][k] = min(dp[j][k], latte[j].rmq(low, k + 1));
dp[j][k] = min(dp[j][k], malta[k].rmq(j, low));
update(j, k);
}
}
cout << dp[0][N - 1] << endl;
}