Problem:
J - 刺身
問題文
きつねのしえるは川で釣りをしていた．黒くて細長い魚を手に入れることができたので，その場で切り刻んで刺身にして食べることにした．
魚は体長が
N
センチメートルある．奇妙なことに，この魚は身体の部分ごとに密度が異なっていた．
魚の身体を頭から 1 センチメートルごとに区切って番号を
1, 2, ..., N
と付けるとき，身体の
i
番目の部分の重みは
w_i
であった．
魚の
i
番目から
j
番目までの部分を
[i..j]
と表すことにする．
最初，しえるは魚の身体
[0..N-1]
を 1 枚だけ持っていると見なせる．しえるはこれを切っていき最終的に
N
個に分割された魚の身体
[0..0], [1..1], ..., [N-1..N-1]
を得たい．
しえるは今野外におり，まな板などを持っていないので，次のようなアクロバティックな方法で魚の身体を切っていくことにした ： まず，魚の身体を 1 枚取る．これを
[i..j]
とする．この魚の身体は長さが少なくとも 2 センチメートル以上でなければならない．すなわち，
j-i ≥ 1
でなければならない．次に，それを空中に投げる．そして日本刀を手に持ち，宙に舞う魚を真っ二つに切る．このとき，しえるは強靭な運動神経によって任意の位置でこの魚を切ることができるが，必ず 1 センチメートル区切りの位置で切るものとする．これにより，元の魚の身体
[i..j]
を，任意の切断位置
k (i ≤ k < j)
によって，
[i..k]
と
[k+1..j]
の 2 つに分割するのである．
このアクロバティックな方法で魚の身体を 2 つに切るとき，元の身体の重さ (=
w
i
+w
i+1
+...+w
j
) だけコストがかかる．
しえるは，魚のすべての部分を 1 センチメートル区切りに切るのにかかるコストの合計値を最小にしたい．
入力形式
入力は以下の形式で与えられる．
N
w
1
w
2
...
w
N
N
は魚の体長である．
w
i
は魚の
i
番目の部分の重さである．
出力形式
魚を
N
個に切り分けるのにかかるコストの合計の最小値を出力せよ．
制約
2 ≤ N ≤ 4,000
1 ≤ w
i
≤ 10
10
入力値はすべて整数である．
この問題の判定には，3 点分のテストケースのグループが設定されている． このグループに含まれるテストケースは上記の制約に加えて下記の制約も満たす．
1 ≤ N ≤ 100
入出力例
入力例 1
3
1 2 3
出力例 1
9
まず，魚全体を 2 番目と 3 番目の部分の間で切る．これには 1+2+3 = 6 のコストがかかる．
次に，1 番目と 2 番目の部分の間で切る．これには 1+2=3 のコストがかかる．合計で 6+3=9 のコストがかかり，これが最善手である．
入力例 2
6
9876543210 9876543210 9876543210 9876543210 9876543210 9876543210
出力例 2
158024691360
入力例 3
10
127 131 137 139 149 151 157 163 167 173
出力例 3
5016
Writer: 楠本充
Tester: 花田裕一朗

Submitted solutions:

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <iostream>
#include <stack>
#include <queue>
#include <algorithm>
#include <functional>
#include <set>
#include <map>
#include <string>
#include <vector>
#include <cmath>
#include<sstream>
#include<list>
#include<iomanip>
#include <cstdlib>
#include <cstring>
#include <stack>
#include <bitset>
#include <cassert>
#include <stdlib.h>
#include <stdio.h>
#include <random>
#include <chrono>
using namespace std;
const long long LINF = 3e18 + 7;
const int MAX_N = 5000010;
const int MAX_W = 10002;
const int MAX_ARRAYK = 100000;
double PI = 3.14159265358979323846;
const int INF = 2147483647;
//using ll = long long;

// 問題
// https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2415

// 参考
// https://omochan.hatenablog.com/entry/2017/07/08/122642
// https://blog.hamayanhamayan.com/entry/2017/03/20/234711

int N;
long long w[MAX_N];
long long cum[MAX_N];
long long dp[4040][4040];
int A[4010][4010];

int main() {

	cin >> N;

	for (int i = 0; i < N; i++) {
		cin >> w[i];
	}
	for (int i = 0; i < N; i++) {
		cum[i + 1] = cum[i] + w[i];
	}
	for (int i = 0; i < N; i++) {
		A[i][i] = i;
	}

	for (int w = 1; w < N; w++) {
		for (int l = 0; l + w <= N; l++) {
			int r = l + w;
			int a = A[l][r - 1];
			int b = A[l + 1][r];
			long long m = LINF;
			int at = -1;
			for (int i = a; i <= b; i++) {
				if (l > i || i >= r) continue;
				long long tm = dp[l][i] + dp[i + 1][r];
				if (tm <= m) {
					at = i;
					m = tm;
				}
			}
			dp[l][r] = m + cum[r + 1] - cum[l];
			A[l][r] = at;
		}
	}

	cout << dp[0][N - 1] << endl;

	return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 195928
final_rank: 4

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <iostream>
#include <stack>
#include <queue>
#include <algorithm>
#include <functional>
#include <set>
#include <map>
#include <string>
#include <vector>
#include <cmath>
#include<sstream>
#include<list>
#include<iomanip>
#include <cstdlib>
#include <cstring>
#include <stack>
#include <bitset>
#include <cassert>
#include <stdlib.h>
#include <stdio.h>
#include <random>
#include <chrono>
using namespace std;
const long long LINF = 3e18 + 7;
const int MAX_N = 5000010;
const int MAX_W = 10002;
const int MAX_ARRAYK = 100000;
double PI = 3.14159265358979323846;
const int INF = 2147483647;
//using ll = long long;

// https://omochan.hatenablog.com/entry/2017/07/08/122642
// https://blog.hamayanhamayan.com/entry/2017/03/20/234711

int N;
long long w[MAX_N];
long long cum[MAX_N];
long long dp[4040][4040];
int A[4010][4010];

int main() {

	cin >> N;

	for (int i = 0; i < N; i++) {
		cin >> w[i];
	}
	for (int i = 0; i < N; i++) {
		cum[i + 1] = cum[i] + w[i];
	}
	for (int i = 0; i < N; i++) {
		A[i][i] = i;
	}

	for (int w = 1; w < N; w++) {
		for (int l = 0; l + w <= N; l++) {
			int r = l + w;
			int a = A[l][r - 1];
			int b = A[l + 1][r];
			long long m = LINF;
			int at = -1;
			for (int i = a; i <= b; i++) {
				if (l > i || i >= r) continue;
				long long tm = dp[l][i] + dp[i + 1][r];
				if (tm <= m) {
					at = i;
					m = tm;
				}
			}
			dp[l][r] = m + cum[r + 1] - cum[l];
			A[l][r] = at;
		}
	}

	cout << dp[0][N - 1] << endl;

	return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 195924
final_rank: 3

code_snippet: #include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
const long long mod=998244353;
const long long mod100=1000000007;
void solve(){
    int N;
    cin>>N;
    ll w[N+1];
    for(int i=1;i<=N;i++) cin>>w[i];
    ll dp[N+1][N+1];
    for(int i=1;i<=N;i++) dp[i][i]=0;
    int K[N+1][N+1];
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++) K[i][j]=-1;
    }
    for(int i=1;i<=N;i++) K[i][i]=i;
    int i,j,r;
    ll sum;
    for(int a=2;a<=N;a++){
        sum=0;
        for(int b=1;b<a;b++) sum+=w[b];
        for(int b=1;b<=N-a+1;b++){
            i=b,j=b+a-1;
            r=-1;
            sum+=w[j];
            for(int k=K[i][j-1];k<=K[i+1][j];k++){
                if(k==j) break;
                if(k==K[i][j-1]){
                    dp[i][j]=dp[i][k]+dp[k+1][j]+sum;
                    r=k;
                    continue;
                }
                if(dp[i][j]>dp[i][k]+dp[k+1][j]+sum){
                    dp[i][j]=dp[i][k]+dp[k+1][j]+sum;
                    r=k;
                }
            }
            K[i][j]=r;
            sum-=w[i];
        }
    }
    cout<<dp[1][N]<<endl;
}
int main(){
    cin.tie(0)->sync_with_stdio(0);
    cout.tie(0);
    solve();
}
accuracy: 0.5681818181818182
time_ms: 20
memory_kb: 51984
final_rank: 17

code_snippet: #include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
const long long mod=998244353;
const long long mod100=1000000007;
void solve(){
    int N;
    cin>>N;
    ll w[N+1];
    for(int i=1;i<=N;i++) cin>>w[i];
    ll sum[N+1][N+1];
    ll dp[N+1][N+1];
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++){
            sum[i][j]=0;
        }
    }
    for(int i=1;i<=N;i++) dp[i][i]=0;
    ll cnt;
    for(int i=1;i<=N;i++){
        cnt=0;
        for(int j=i;j<=N;j++){
            cnt+=w[j];
            sum[i][j]=cnt;
        }
    }
    int K[N+1][N+1];
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++) K[i][j]=-1;
    }
    for(int i=1;i<=N;i++) K[i][i]=i;
    int i,j,r;
    for(int a=2;a<=N;a++){
        for(int b=1;b<=N-a+1;b++){
            i=b,j=b+a-1;
            r=-1;
            for(int k=K[i][j-1];k<=K[i+1][j];k++){
                if(k==j) break;
                if(k==K[i][j-1]){
                    dp[i][j]=dp[i][k]+dp[k+1][j]+sum[i][j];
                    r=k;
                    continue;
                }
                if(dp[i][j]>dp[i][k]+dp[k+1][j]+sum[i][j]){
                    dp[i][j]=dp[i][k]+dp[k+1][j]+sum[i][j];
                    r=k;
                }
            }
            K[i][j]=r;
        }
    }
    cout<<dp[1][N]<<endl;
}
int main(){
    cin.tie(0)->sync_with_stdio(0);
    cout.tie(0);
    solve();
}
accuracy: 0.5681818181818182
time_ms: 20
memory_kb: 85168
final_rank: 18

code_snippet: #include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
const long long mod=998244353;
const long long mod100=1000000007;
void solve(){
    int N;
    cin>>N;
    ll w[N+1];
    for(int i=1;i<=N;i++) cin>>w[i];
    ll sum[N+1][N+1];
    ll dp[N+1][N+1];
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++){
            sum[i][j]=0;
            dp[i][j]=2e18;
        }
    }
    for(int i=1;i<=N;i++) dp[i][i]=0;
    for(int i=1;i<=N;i++){
        ll cnt=0;
        for(int j=i;j<=N;j++){
            cnt+=w[j];
            sum[i][j]=cnt;
        }
    }
    int K[N+1][N+1];
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++) K[i][j]=-1;
    }
    for(int i=1;i<=N;i++) K[i][i]=i;
    int i,j,r;
    for(int a=2;a<=N;a++){
        for(int b=1;b<=N-a+1;b++){
            i=b,j=b+a-1;
            r=-1;
            for(int k=K[i][j-1];k<=K[i+1][j];k++){
                if(k==j) break;
                if(dp[i][j]>dp[i][k]+dp[k+1][j]+sum[i][j]){
                    dp[i][j]=dp[i][k]+dp[k+1][j]+sum[i][j];
                    r=k;
                }
            }
            K[i][j]=r;
        }
    }
    cout<<dp[1][N]<<endl;
}
int main(){
    cin.tie(0)->sync_with_stdio(0);
    cout.tie(0);
    solve();
}
accuracy: 0.5681818181818182
time_ms: 20
memory_kb: 85364
final_rank: 19

code_snippet: #include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
const long long mod=998244353;
const long long mod100=1000000007;
void solve(){
    int N;
    cin>>N;
    ll w[N+1];
    for(int i=1;i<=N;i++) cin>>w[i];
    ll sum[N+1][N+1];
    ll dp[N+1][N+1];
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++){
            sum[i][j]=0;
            dp[i][j]=2e18;
        }
    }
    for(int i=1;i<=N;i++) dp[i][i]=0;
    for(int i=1;i<=N;i++){
        ll cnt=0;
        for(int j=i;j<=N;j++){
            cnt+=w[j];
            sum[i][j]=cnt;
        }
    }
    int K[N+1][N+1];
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++) K[i][j]=-1;
    }
    for(int i=1;i<=N;i++) K[i][i]=i;

    for(int a=2;a<=N;a++){
        for(int b=1;b<=N-a+1;b++){
            int i=b,j=b+a-1;
            int r=-1;
            for(int k=K[i][j-1];k<=K[i+1][j];k++){
                if(k==j) break;
                ll now=dp[i][k]+dp[k+1][j]+sum[i][j];
                if(dp[i][j]>now){
                    dp[i][j]=now;
                    r=k;
                }
            }
            K[i][j]=r;
        }
    }
    cout<<dp[1][N]<<endl;
}
int main(){
    cin.tie(0)->sync_with_stdio(0);
    cout.tie(0);
    solve();
}
accuracy: 0.5681818181818182
time_ms: 40
memory_kb: 85336
final_rank: 20

code_snippet: #include <bits/stdc++.h>

#define SQR(x)    (1LL * ((x) * (x)))
#define MASK(i)   (1LL << (i))
#define BIT(x, i) (((x) >> (i)) & 1)
#define fi        first
#define se        second
#define pb        push_back
#define all(x)    x.begin(), x.end()
#define rall(x)   x.rbegin(), x.rend()
#define sz(s)     (int)s.size()
#define prev      __prev
#define next      __next
#define left      __left
#define right     __right

#define mp make_pair
#define pii pair<int, int>
#define pll pair<ll, ll>
#define vi vector<int>
#define vll vector<ll>

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef unsigned int ui;

using namespace std;

const int mod = 1e9 + 7;
const int INF = 1e9 + 7;
const ll INFLL = (ll)2e18 + 7LL;
const ld PI = acos(-1);

const int dx[] = {1, -1, 0, 0, -1, 1, 1, -1};
const int dy[] = {0, 0, 1, -1, -1, -1, 1, 1};

template<class BUI, class TRONG>
    bool minimize(BUI &x, const TRONG y){
        if(x > y){
            x = y;
            return true;
        } else return false;
    }
template<class BUI, class TRONG>
    bool maximize(BUI &x, const TRONG y){
        if(x < y){
            x = y;
            return true;
        } else return false;
    }

/* Author : Bui Nguyen Duc Trong, Luong Van Chanh High School for the gifted*/
/* Template is copied by Trong */

                           /** Losing in Provincial Contests **/
                                    /** TRYING HARDER**/
                                   /**      ORZ     **/

/* -----------------[ MAIN CODE GOES HERE ]----------------- */

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const int N = 4040;

int n;
ll f[N][N], w[N];
int opt[N][N];

ll getRange(int i, int j) { return w[j] - w[i - 1]; }

void solve(){
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> w[i], w[i] += w[i - 1];
    memset(f, 0x3f, sizeof f);
    for(int i = 1; i <= n; i++) f[i][i] = 0, opt[i][i] = i;
    for(int l = 2; l <= n; l++) for(int i = 1; i + l - 1 <= n; i++){
        int j = i + l - 1;
        for(int k = opt[i][j - 1]; k <= opt[i + 1][j]; k++){
            if(k < j && minimize(f[i][j], f[i][k] + f[k + 1][j] + getRange(i, j))) opt[i][j] = k;
        }
    }
    cout << f[1][n] << '\n';
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    const bool multitest = 0;
    int tt = 1; if(multitest) cin >> tt;

    while( tt-- ){

        solve();

    }

    return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 194724
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
#include <atcoder/all>
using namespace atcoder;

#define overload4(_1, _2, _3, _4, name, ...) name
#define rep1(n) for(ll i = 0; i < (n); ++i)
#define rep2(i, n) for(ll i = 0; i < (n); ++i)
#define rep3(i, a, b) for(ll i = (a); i < (b); ++i)
#define rep4(i, a, b, c) for(ll i = (a); i < (b); i += (c))
#define rep(...) overload4(__VA_ARGS__, rep4, rep3, rep2, rep1)(__VA_ARGS__)
#define all(x) x.begin(), x.end()

using ll = long long;
template<class T> using pq = priority_queue<T, vector<T>, greater<T>>;
using pll = pair<ll, ll>;

const int INF = 1 << 29;  const ll LINF = 0x1fffffffffffffff;
const ll MOD = 998244353;  const ll MOD2 = 1000000007;

template<class T, size_t n, size_t idx = 0>
auto make_vec(const size_t (&d)[n], const T& init) noexcept {
    if constexpr (idx < n) return std::vector(d[idx], make_vec<T, n, idx + 1>(d, init));
    else return init;
}
template<class T, size_t n>
auto make_vec(const size_t (&d)[n]) noexcept {
    return make_vec(d, T{});
}

struct Edge{ int to; ll cost; };


//======================================================================================================

ll N;
vector<ll> w;
vector<vector<ll>> dp, K;

int main(){
    cin >> N;
    w.resize(N);
    rep(i, N) cin >> w[i];
    dp.resize(N+1, vector<ll>(N+1, LINF));
    K.resize(N+1, vector<ll>(N+1));

    // 累積和
    vector<ll> ws({0});
    rep(i, N) ws.push_back(ws[i] + w[i]);

    // 区間DP, Monge性を用いてO(n^2)
    // K[i][j] = (dp[i][s] + dp[s+1][j]) がminとなる最大のs
    // sの探索範囲を K[i-1][j] ~ K[i][j-1] に狭められる
    rep(i, N){
        dp[i][i] = 0;
        K[i][i] = i;
    }

    rep(d, 1, N){
        rep(i, N){
            ll j = i + d;
            if (j >= N) continue;
            ll l = K[i][j-1];
            ll r = K[i+1][j];
            rep(s, l, r+1){
                if (dp[i][s] + dp[s+1][j] <= dp[i][j]){
                    dp[i][j] = dp[i][s] + dp[s+1][j];
                    K[i][j] = s;
                }
            }
            dp[i][j] += ws[j+1] - ws[i];
        }
    }

    cout << dp[0][N-1] << endl;
}
accuracy: 1
time_ms: 230
memory_kb: 254080
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
#include <atcoder/all>
using namespace atcoder;

#define overload4(_1, _2, _3, _4, name, ...) name
#define rep1(n) for(ll i = 0; i < (n); ++i)
#define rep2(i, n) for(ll i = 0; i < (n); ++i)
#define rep3(i, a, b) for(ll i = (a); i < (b); ++i)
#define rep4(i, a, b, c) for(ll i = (a); i < (b); i += (c))
#define rep(...) overload4(__VA_ARGS__, rep4, rep3, rep2, rep1)(__VA_ARGS__)
#define all(x) x.begin(), x.end()

using ll = long long;
template<class T> using pq = priority_queue<T, vector<T>, greater<T>>;
using pll = pair<ll, ll>;

const int INF = 1 << 29;  const ll LINF = 0x1fffffffffffffff;
const ll MOD = 998244353;  const ll MOD2 = 1000000007;

template<class T, size_t n, size_t idx = 0>
auto make_vec(const size_t (&d)[n], const T& init) noexcept {
    if constexpr (idx < n) return std::vector(d[idx], make_vec<T, n, idx + 1>(d, init));
    else return init;
}
template<class T, size_t n>
auto make_vec(const size_t (&d)[n]) noexcept {
    return make_vec(d, T{});
}

struct Edge{ int to; ll cost; };


//======================================================================================================

ll N;
vector<ll> w;
vector<vector<ll>> dp, K;

int main(){
    cin >> N;
    w.resize(N);
    rep(i, N) cin >> w[i];
    dp.resize(N+1, vector<ll>(N+1, LINF));
    K.resize(N+1, vector<ll>(N+1));

    // 累積和
    vector<ll> ws({0});
    rep(i, N) ws.push_back(ws[i] + w[i]);

    // 区間DP, Monge性を用いてO(n^2)
    // K[i][j] = (dp[i][s] + dp[s+1][j]) がminとなる最大のs
    // sの探索範囲を K[i-1][j] ~ K[i][j-1] に狭められる
    rep(i, N){
        dp[i][i] = 0;
        K[i][i] = i;
    }

    rep(d, 1, N){
        rep(i, N){
            ll j = i + d;
            if (j >= N) continue;
            ll l = K[i][j-1];
            ll r = K[i+1][j];
            rep(s, l, r+1){
                if (dp[i][s] + dp[s+1][j] <= dp[i][j]){
                    dp[i][j] = dp[i][s] + dp[s+1][j];
                    K[i][j] = s;
                }
            }
            dp[i][j] += ws[j+1] - ws[i];
        }
    }

    cout << dp[0][N-1] << endl;
}
accuracy: 1
time_ms: 230
memory_kb: 254080
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
#include <atcoder/all>
using namespace atcoder;

#define overload4(_1, _2, _3, _4, name, ...) name
#define rep1(n) for(ll i = 0; i < (n); ++i)
#define rep2(i, n) for(ll i = 0; i < (n); ++i)
#define rep3(i, a, b) for(ll i = (a); i < (b); ++i)
#define rep4(i, a, b, c) for(ll i = (a); i < (b); i += (c))
#define rep(...) overload4(__VA_ARGS__, rep4, rep3, rep2, rep1)(__VA_ARGS__)
#define all(x) x.begin(), x.end()

using ll = long long;
template<class T> using pq = priority_queue<T, vector<T>, greater<T>>;
using pll = pair<ll, ll>;

const int INF = 1 << 29;  const ll LINF = 0x1fffffffffffffff;
const ll MOD = 998244353;  const ll MOD2 = 1000000007;

template<class T, size_t n, size_t idx = 0>
auto make_vec(const size_t (&d)[n], const T& init) noexcept {
    if constexpr (idx < n) return std::vector(d[idx], make_vec<T, n, idx + 1>(d, init));
    else return init;
}
template<class T, size_t n>
auto make_vec(const size_t (&d)[n]) noexcept {
    return make_vec(d, T{});
}

struct Edge{ int to; ll cost; };


//======================================================================================================

ll N;
vector<ll> w;
vector<vector<ll>> dp, K;

int main(){
    cin >> N;
    w.resize(N);
    rep(i, N) cin >> w[i];
    dp.resize(N+1, vector<ll>(N+1, LINF));
    K.resize(N+1, vector<ll>(N+1));
    
    // 区間DP, Monge性

    rep(i, N){
        dp[i][i] = 0;
        K[i][i] = i;
    }
    vector<ll> ws({0});
    rep(i, N) ws.push_back(ws[i] + w[i]);

    rep(d, 1, N){
        rep(i, N){
            ll j = i + d;
            if (j >= N) continue;
            ll l = K[i][j-1];
            ll r = K[i+1][j];
            rep(s, l, r+1){
                if (dp[i][s] + dp[s+1][j] <= dp[i][j]){
                    dp[i][j] = dp[i][s] + dp[s+1][j];
                    K[i][j] = s;
                }
            }
            dp[i][j] += ws[j+1] - ws[i];
        }
    }

    cout << dp[0][N-1] << endl;
}
accuracy: 1
time_ms: 230
memory_kb: 254080
final_rank: 12

code_snippet: #ifndef HIDDEN_IN_VS // 折りたたみ用

// 警告の抑制
#define _CRT_SECURE_NO_WARNINGS

// ライブラリの読み込み
#include <bits/stdc++.h>
using namespace std;

// 型名の短縮
using ll = long long; using ull = unsigned long long; // -2^63 ～ 2^63 = 9e18（int は -2^31 ～ 2^31 = 2e9）
using pii = pair<int, int>;	using pll = pair<ll, ll>;	using pil = pair<int, ll>;	using pli = pair<ll, int>;
using vi = vector<int>;		using vvi = vector<vi>;		using vvvi = vector<vvi>;	using vvvvi = vector<vvvi>;
using vl = vector<ll>;		using vvl = vector<vl>;		using vvvl = vector<vvl>;	using vvvvl = vector<vvvl>;
using vb = vector<bool>;	using vvb = vector<vb>;		using vvvb = vector<vvb>;
using vc = vector<char>;	using vvc = vector<vc>;		using vvvc = vector<vvc>;
using vd = vector<double>;	using vvd = vector<vd>;		using vvvd = vector<vvd>;
template <class T> using priority_queue_rev = priority_queue<T, vector<T>, greater<T>>;
using Graph = vvi;

// 定数の定義
const double PI = acos(-1);
int DX[4] = { 1, 0, -1, 0 }; // 4 近傍（下，右，上，左）
int DY[4] = { 0, 1, 0, -1 };
int INF = 1001001001; ll INFL = 4004004003094073385LL; // (int)INFL = INF, (int)(-INFL) = -INF;

// 入出力高速化
struct fast_io { fast_io() { cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(18); } } fastIOtmp;

// 汎用マクロの定義
#define all(a) (a).begin(), (a).end()
#define sz(x) ((int)(x).size())
#define lbpos(a, x) (int)distance((a).begin(), std::lower_bound(all(a), (x)))
#define ubpos(a, x) (int)distance((a).begin(), std::upper_bound(all(a), (x)))
#define Yes(b) {cout << ((b) ? "Yes\n" : "No\n");}
#define rep(i, n) for(int i = 0, i##_len = int(n); i < i##_len; ++i) // 0 から n-1 まで昇順
#define repi(i, s, t) for(int i = int(s), i##_end = int(t); i <= i##_end; ++i) // s から t まで昇順
#define repir(i, s, t) for(int i = int(s), i##_end = int(t); i >= i##_end; --i) // s から t まで降順
#define repe(v, a) for(const auto& v : (a)) // a の全要素（変更不可能）
#define repea(v, a) for(auto& v : (a)) // a の全要素（変更可能）
#define repb(set, d) for(int set = 0, set##_ub = 1 << int(d); set < set##_ub; ++set) // d ビット全探索（昇順）
#define repis(i, set) for(int i = lsb(set), bset##i = set; i < 32; bset##i -= 1 << i, i = lsb(bset##i)) // set の全要素（昇順）
#define repp(a) sort(all(a)); for(bool a##_perm = true; a##_perm; a##_perm = next_permutation(all(a))) // a の順列全て（昇順）
#define uniq(a) {sort(all(a)); (a).erase(unique(all(a)), (a).end());} // 重複除去
#define EXIT(a) {cout << (a) << endl; exit(0);} // 強制終了
#define inQ(x, y, u, l, d, r) ((u) <= (x) && (l) <= (y) && (x) < (d) && (y) < (r)) // 半開矩形内判定

// 汎用関数の定義
template <class T> inline ll powi(T n, int k) { ll v = 1; rep(i, k) v *= n; return v; }
template <class T> inline bool chmax(T& M, const T& x) { if (M < x) { M = x; return true; } return false; } // 最大値を更新（更新されたら true を返す）
template <class T> inline bool chmin(T& m, const T& x) { if (m > x) { m = x; return true; } return false; } // 最小値を更新（更新されたら true を返す）
template <class T> inline T getb(T set, int i) { return (set >> i) & T(1); }
template <class T> inline T smod(T n, T m) { n %= m; if (n < 0) n += m; return n; } // 非負mod

// 演算子オーバーロード
template <class T, class U> inline istream& operator>>(istream& is, pair<T, U>& p) { is >> p.first >> p.second; return is; }
template <class T> inline istream& operator>>(istream& is, vector<T>& v) { repea(x, v) is >> x; return is; }
template <class T> inline vector<T>& operator--(vector<T>& v) { repea(x, v) --x; return v; }
template <class T> inline vector<T>& operator++(vector<T>& v) { repea(x, v) ++x; return v; }

#endif // 折りたたみ用


#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;

#ifdef _MSC_VER
#include "localACL.hpp"
#endif

//using mint = modint1000000007;
using mint = modint998244353;
//using mint = static_modint<1000000000>;
//using mint = modint; // mint::set_mod(m);

namespace atcoder {
	inline istream& operator>>(istream& is, mint& x) { ll x_; is >> x_; x = x_; return is; }
	inline ostream& operator<<(ostream& os, const mint& x) { os << x.val(); return os; }
}
using vm = vector<mint>; using vvm = vector<vm>; using vvvm = vector<vvm>; using vvvvm = vector<vvvm>; using pim = pair<int, mint>;
#endif


#ifdef _MSC_VER // 手元環境（Visual Studio）
#include "local.hpp"
#else // 提出用（gcc）
inline int popcount(int n) { return __builtin_popcount(n); }
inline int popcount(ll n) { return __builtin_popcountll(n); }
inline int lsb(int n) { return n != 0 ? __builtin_ctz(n) : 32; }
inline int lsb(ll n) { return n != 0 ? __builtin_ctzll(n) : 64; }
template <size_t N> inline int lsb(const bitset<N>& b) { return b._Find_first(); }
inline int msb(int n) { return n != 0 ? (31 - __builtin_clz(n)) : -1; }
inline int msb(ll n) { return n != 0 ? (63 - __builtin_clzll(n)) : -1; }
#define dump(...)
#define dumpel(...)
#define dump_list(v)
#define dump_mat(v)
#define input_from_file(f)
#define output_to_file(f)
#define Assert(b) { if (!(b)) { vc MLE(1<<30); EXIT(MLE.back()); } } // RE の代わりに MLE を出す
#endif


//【Knuth-Yao speedup】
/*
* 与えられた Monge かつ単調なコスト c[0..n][0..n] に対し，
*	dp[l][r] = MIN_m∈(l..r) (dp[l][m] + dp[m][r]) + c[l][r]
* で定まる dp[0..n][0..n] を返す．
* 
* c が単調であるとは，
*	∀l1, r1, l2, r2, [l1..r1) ⊂ [l2..r2) ⇒ c[l1][r1] ≦ c[l2][r2]
* が成り立つことをいう．
*/
template <class T>
vector<vector<T>> knuth_yao_speedup(const vector<vector<T>>& c) {
	int n = sz(c) - 1;

	// dp[l][r] : [l..r) のマージにかかる最小コスト
	vector<vector<T>> dp(n + 1, vector<T>(n + 1, INFL));
	rep(l, n) dp[l][l + 1] = c[l][l + 1];

	// sp[l][r] = m : [l..m) と [m..r) を最後にマージしたことを表す．
	vvi sp(n + 1, vi(n + 1, -1));
	rep(i, n) sp[i][i + 1] = i + 1;

	repir(l, n - 2, 0) repi(r, l + 2, n) {
		// [l..m) と [m..r) を最後にマージする場合を考える．
		//	調べる k の範囲を 1 つ短い区間の分割位置の間に限定している．
		repi(m, sp[l][r - 1], sp[l + 1][r]) {
			if (chmin(dp[l][r], dp[l][m] + dp[m][r])) sp[l][r] = m;
		}

		// [l..m) と [m..r) のマージにかかる m に依らないコストを加算する．
		dp[l][r] += c[l][r];
	}

	return dp;
}


void MLE() {
	int n;
	cin >> n;

	vl w(n);
	cin >> w;

	vl acc(n + 1);
	rep(i, n) acc[i + 1] = acc[i] + w[i];

	vvl cost(n + 1, vl(n + 1));
	rep(l, n) repi(r, l + 2, n) cost[l][r] = acc[r] - acc[l];
	dumpel(cost);

	auto dp = knuth_yao_speedup(cost);
	dumpel(dp);

	EXIT(dp[0][n]);
}


//【Knuth-Yao speedup】
/*
* 与えられた Monge かつ単調なコスト c[0..n][0..n] に対し，
*	dp[l][r] = MIN_m∈(l..r) (dp[l][m] + dp[m][r]) + c[l][r]
* で定まる dp[0..n][0..n] を返す．
*
* c が単調であるとは，
*	∀l1, r1, l2, r2, [l1..r1) ⊂ [l2..r2) ⇒ c[l1][r1] ≦ c[l2][r2]
* が成り立つことをいう．
*/
template <class F>
vvl knuth_yao_speedup_func(int n, const F& c) {
	// dp[l][r] : [l..r) のマージにかかる最小コスト
	vvl dp(n + 1, vl(n + 1, INFL));
	rep(l, n) dp[l][l + 1] = c(l, l + 1);

	// sp[l][r] = m : [l..m) と [m..r) を最後にマージしたことを表す．
	vvi sp(n + 1, vi(n + 1, -1));
	rep(i, n) sp[i][i + 1] = i + 1;

	repir(l, n - 2, 0) repi(r, l + 2, n) {
		// [l..m) と [m..r) を最後にマージする場合を考える．
		//	調べる k の範囲を 1 つ短い区間の分割位置の間に限定している．
		repi(m, sp[l][r - 1], sp[l + 1][r]) {
			if (chmin(dp[l][r], dp[l][m] + dp[m][r])) sp[l][r] = m;
		}

		// [l..m) と [m..r) のマージにかかる m に依らないコストを加算する．
		dp[l][r] += c(l, r);
	}

	return dp;
}


int main() {
//	input_from_file("input.txt");
//	output_to_file("output.txt");

	int n;
	cin >> n;

	vl w(n);
	cin >> w;

	vl acc(n + 1);
	rep(i, n) acc[i + 1] = acc[i] + w[i];

	auto cost = [&](int l, int r) {
		if (r - l <= 1) return 0LL;
		return acc[r] - acc[l];
	};

	auto dp = knuth_yao_speedup_func(n, cost);
	dumpel(dp);

	EXIT(dp[0][n]);
}
accuracy: 1
time_ms: 130
memory_kb: 191056
final_rank: 5

code_snippet: #include <bits/stdc++.h>

using namespace std;
#define endl "\n"
typedef long long ll;
const int N = 4005;
#define int long long
int w[N];
int dp[N][N], loc[N][N];
void solved() {
  int n;
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> w[i];
    w[i] += w[i - 1];
  }
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
      dp[i][j] = 1e18;
      if (i == j) {
        dp[i][j] = 0;
        loc[i][j] = i;
      }
    }
  }
  ll tmp;
  for (int len = 1; len <= n; len++) {
    for (int i = 1; i + len - 1 <= n; i++) {
      int j = i + len - 1;
      for (int k = loc[i][j - 1]; k <= loc[i + 1][j]; k++) {
        tmp = dp[i][k] + dp[k + 1][j] + w[j] - w[i - 1];
        if (tmp < dp[i][j]) {
          dp[i][j] = tmp;
          loc[i][j] = k;
        }
      }
    }
  }
  cout << dp[1][n] << endl;
}
signed main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
 
  solved();

  return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 253888
final_rank: 8

code_snippet: #include <bits/stdc++.h>

using namespace std;
#define endl "\n"
typedef long long ll;
const int N = 4005;
#define int long long
int w[N];
int dp[N][N], loc[N][N];
void solved() {
  int n;
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> w[i];
    w[i] += w[i - 1];
  }
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
      dp[i][j] = 1e18;
      if (i == j) {
        dp[i][j] = 0;
        loc[i][j] = i;
      }
    }
  }
  ll tmp;
  for (int len = 1; len <= n; len++) {
    for (int i = 1; i + len - 1 <= n; i++) {
      int j = i + len - 1;
      for (int k = loc[i][j - 1]; k <= loc[i + 1][j]; k++) {
        tmp = dp[i][k] + dp[k + 1][j] + w[j] - w[i - 1];
        if (tmp < dp[i][j]) {
          dp[i][j] = tmp;
          loc[i][j] = k;
        }
      }
    }
  }
  cout << dp[1][n] << endl;
}
signed main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  /*int t = 1;
  cin >> t;
  while (t--)*/
  solved();

  return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 253996
final_rank: 9

code_snippet: #include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cfloat>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <time.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define HUGE_NUM 9999999999999999

int N;
ll W[4001],dp[4000][4000];
int loc[4000][4000];

int main(){

	scanf("%d",&N);
	for(int i = 0; i < N; i++){
		for(int k = i; k < N; k++)dp[i][k] = HUGE_NUM;
	}

	W[0] = 0;
	for(int i = 1; i <= N; i++){
		scanf("%lld",&W[i]);
		W[i] += W[i-1];
	}

	for(int i = 0; i < N; i++){
		dp[i][i] = 0;
		loc[i][i] = i;
	}

	int right;
	ll tmp;
	for(int length = 2; length <= N; length++){
		for(int left = 0; left+length-1 <= N-1; left++){
			right = left+length-1;
			for(int mid = loc[left][right-1]; mid <= loc[left+1][right]; mid++){
				tmp = dp[left][mid]+dp[mid+1][right]+W[right+1]-W[left];
				if(tmp < dp[left][right]){
					dp[left][right] = tmp;
					loc[left][right] = mid;
				}
			}
		}
	}

	printf("%lld\n",dp[0][N-1]);
}
accuracy: 1
time_ms: 100
memory_kb: 190100
final_rank: 2

code_snippet: #include <iostream>
#include <vector>
#include <climits>

using namespace std;

int main() {
    int numElements;
    cin >> numElements;
    
    vector<long long> weights(numElements);
    for (auto& weight : weights) {
        cin >> weight;
    }

    // 累積和を格納するベクター。sumWeights[i]はweightsの最初のi個の要素の合計
    vector<long long> sumWeights(numElements + 1, 0);
    for (int i = 0; i < numElements; ++i) {
        sumWeights[i + 1] = sumWeights[i] + weights[i];
    }

    // 分割点を記録するためのテーブル
    vector<vector<int>> optimalCut(numElements, vector<int>(numElements));
    
    // 各区間の最小コストを記録するテーブル
    vector<vector<long long>> minCost(numElements, vector<long long>(numElements, 0));

    // 初期化: 長さ2の区間についての最小コストと分割点を計算
    for (int i = 0; i + 1 < numElements; ++i) {
        optimalCut[i][i + 1] = i;
        minCost[i][i + 1] = sumWeights[i + 2] - sumWeights[i];
    }

    // 動的計画法による最小コストの計算
    for (int length = 2; length < numElements; ++length) {
        for (int start = 0; start + length < numElements; ++start) {
            int end = start + length;
            long long minTotalCost = LLONG_MAX;
            int bestCut = -1;

            // 分割点を最適化するループ
            for (int mid = optimalCut[start][end - 1]; mid <= optimalCut[start + 1][end]; ++mid) {
                long long currentCost = minCost[start][mid] + minCost[mid + 1][end];
                if (currentCost < minTotalCost) {
                    minTotalCost = currentCost;
                    bestCut = mid;
                }
            }

            minCost[start][end] = minTotalCost + sumWeights[end + 1] - sumWeights[start];
            optimalCut[start][end] = bestCut;
        }
    }

    // 最終結果の出力: 配列全体を統合する最小コスト
    cout << minCost[0][numElements - 1] << endl;

    return 0;
}
accuracy: 1
time_ms: 220
memory_kb: 191124
final_rank: 7

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <iostream>
#include <stack>
#include <queue>
#include <algorithm>
#include <functional>
#include <set>
#include <map>
#include <string>
#include <vector>
#include <cmath>
#include<sstream>
#include<list>
#include<iomanip>
#include <cstdlib>
#include <cstring>
#include <stack>
#include <bitset>
#include <cassert>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
const int INF = 1000000007;
const long long LINF = 3e18 + 7;
const int MAX_N = 1200010;
const int MAX_W = 600010;
const int MAX_ARRAYK = 100000;
double PI = 3.14159265358979323846;
//using ll = long long;


// https://omochan.hatenablog.com/entry/2017/07/08/122642

// 補足: https://sssslide.com/www.slideshare.net/ikumihide/ss-50881829
// 補足: https://blog.hamayanhamayan.com/entry/2017/03/20/234711

int N;
long long dp[4010][4010];
long long w[4010];
long long S[4010];
int A[4010][4010];

int main() {

	cin >> N;
	for (int i = 0; i < N; i++) {
		cin >> w[i];
	}

	for (int i = 0; i < N; i++) {
		S[i + 1] = S[i] + w[i];
	}

	for (int i = 0; i < N; i++) {
		A[i][i] = i;
	}
	
	for (int k = 1; k < N; k++) {
		for (int i = 0; i <= N - k; i++) {
			int j = i + k;
			int a = A[i][j - 1];
			int b = A[i + 1][j];
			long long m = LINF;
			int at = -1;
			for (int l = a; l <= b; l++) {
				if (i > l || l >= j)continue;
				long long tm = dp[i][l] + dp[l + 1][j];
				if (tm <= m) {
					at = l;
					m = tm;
				}
			}

			dp[i][j] = m + S[j + 1] - S[i];
			A[i][j] = at;
		}
	}

	cout << dp[0][N - 1] << endl;



	return 0;
}
accuracy: 1
time_ms: 370
memory_kb: 125952
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll=int64_t;

int main(){
  int n;
  cin >> n;
  
  vector<ll> w(n+1,0);
  vector<ll> wsm(n+1,0);
  for(int i=1;i<=n;i++){
    cin >> w[i];
    wsm[i]=wsm[i-1]+w[i];
  } 
  if(n==2){
    cout << wsm[2] << endl;
    return 0;
  }
  
  vector dp(n+1,vector<ll>(n+1,LLONG_MAX));
  vector m(n+1,vector<int>(n+1));
  for(int i=1;i<=n;i++){
    dp[i][i]=0;
    m[i][i]=i;
    if(i<n){ 
      dp[i][i+1]=w[i]+w[i+1];
      m[i][i+1]=i;
    }
  }
  

  
  for(int k=2;k<n;k++){
    for(int i=1;i<=n-k;i++){
      for(int j=m[i][i+k-1];j<=m[i+1][i+k];j++){
        if(dp[i][i+k]>dp[i][j]+dp[j+1][i+k]){
          dp[i][i+k]=dp[i][j]+dp[j+1][i+k];
          m[i][i+k]=j;
        }
      }
      dp[i][i+k]+=wsm[i+k]-wsm[i-1];
    }
  }

  cout << dp[1][n] << endl;
}
accuracy: 1
time_ms: 220
memory_kb: 191080
final_rank: 6

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = (1LL<<60);
int n;
ll w, rui[4004], cut[4004][4004], dp[4004][4004];
int main(){
    cin >> n;
    rui[0] = 0;
    for(int i=1;i<=n;i++){
        cin >> w;
        rui[i] = w+rui[i-1];
        cut[i][i] = i;
        for(int j=i+1;j<=n;j++) dp[i][j] = INF;
        dp[i][i] = 0;
    }
    for(int i=1;i<=n;i++){
        for(int l=1;l<=n-i;l++){
            int r = l+i;
            for(int k=cut[l][r-1];k<=cut[l+1][r];k++){
                ll ncut = dp[l][k] + dp[k+1][r] + rui[r]-rui[l-1];
                if(dp[l][r] > ncut){
                    dp[l][r] = ncut;
                    cut[l][r] = k;
                }
            }
        }
    }
    cout << dp[1][n] << endl;
    return(0);
}
accuracy: 1
time_ms: 400
memory_kb: 158160
final_rank: 11

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = (1LL<<60);
int n;
ll w, rui[4004], cut[4004][4004], dp[4004][4004];
int main(){
    cin >> n;
    rui[0] = 0;
    for(int i=1;i<=n;i++){
        cin >> w;
        rui[i] = w+rui[i-1];
        cut[i][i] = i;
        for(int j=1;j<=n;j++) dp[i][j] = INF;
        dp[i][i] = 0;
    }
    for(int i=1;i<=n;i++){
        for(int l=1;l<=n-i;l++){
            int r = l+i;
            for(int k=cut[l][r-1];k<=cut[l+1][r];k++){
                ll ncut = dp[l][k] + dp[k+1][r] + rui[r]-rui[l-1];
                if(dp[l][r] > ncut){
                    dp[l][r] = ncut;
                    cut[l][r] = k;
                }
            }
        }
    }
    cout << dp[1][n] << endl;
    return(0);
}
accuracy: 1
time_ms: 420
memory_kb: 205764
final_rank: 15

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = (1LL<<60);
int n;
ll w, rui[4004], cut[4004][4004], dp[4004][4004];
int main(){
    cin >> n;
    rui[0] = 0;
    fill_n(*dp, 4004*4004, INF);
    for(int i=1;i<=n;i++){
        cin >> w;
        rui[i] = w+rui[i-1];
        cut[i][i] = i;
        dp[i][i] = 0;
    }
    for(int i=1;i<=n;i++){
        for(int l=1;l<=n-i;l++){
            int r = l+i;
            for(int k=cut[l][r-1];k<=cut[l+1][r];k++){
                ll ncut = dp[l][k] + dp[k+1][r] + rui[r]-rui[l-1];
                if(dp[l][r] > ncut){
                    dp[l][r] = ncut;
                    cut[l][r] = k;
                }
            }
        }
    }
    cout << dp[1][n] << endl;
    return(0);
}
accuracy: 1
time_ms: 420
memory_kb: 205884
final_rank: 16