Problem:
お菓子の分割
　

問題

長さ N ミリメートルの棒状のお菓子が 1 本ある(ここで N は偶数). 2 人の JOI
関係者が,このお菓子を複数本に切断して,合計 N/2 ミリメートルずつに分けること
にした.

理由は不明であるが,このお菓子は場所によって切断のしやすさが異なっている.
2 人は,お菓子を左から 1 ミリメートルごとに調べ,各場所で切断に何秒かかるか
を割り出した.2 人がお菓子を分けるための切断にかかる秒数の最小値を求めるプ
ログラムを作成せよ.

入力

入力の 1 行目には,棒の長さ N(2 ≤ N ≤ 10000 ,ただし N は偶数) が書かれてい
る.入力の i + 1 行目 (1 ≤ i ≤ N − 1) には,左端から i ミリメートル目の場所の切
断にかかる秒数を表す整数 ti (1 ≤ ti ≤ 10000) が書かれている.切断可能な場所が
N − 1 箇所であることに注意せよ.

採点用データのうち,配点の 5% 分については,高々 2 カ所を切断することで最
小値を実現でき,10% 分については,高々 3 カ所を切断することで最小値を実現で
きる.配点の 20% 分については,N ≤ 20 である.

出力

出力は2 人がお菓子を分るための切断にかかる秒数の最小値を含む 1 行からなる.

入出力例

入力例 1

6
1
8
12
6
2

出力例 1

7

この場合,左端から 1 ミリメートルと 4 ミリメートルの場所で切断するとかかる
秒数が最小となる.かかる秒数は 1 秒と 6 秒で,合計 7 秒である.

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

Solution in C (judge verdict: Accepted)

#include <stdio.h>
#include <string.h>

#define INF (1 << 30)

int min(int a, int b)
{
    return (b > a ? a : b);
}

/*
int memo(int b, int w, int col)
{
    int ans;
    
    if (w == n / 2){
        return (0);
    }
    
    if (dp[b][w][col] >= 0){
        return (dp[b][w][col]);
    }
    
    ans = 1 << 30;
    if (col == 0){
        if (w < n / 2){
            ans = min(ans, memo(b, w + 1, col));
        }
        if (b < n / 2){
            ans = min(ans, memo(b ^ 1, w, col ^ 1) + div[b + w]);
        }
    }
    else {
        if (b < n / 2){
            ans = min(ans, memo(b ^ 1, w, col));
        }
        if (w < n / 2){
            ans = min(ans, memo(b, w + 1, col ^ 1) + div[b + w]);
        }
    }
    
    return (dp[b][w][col] = ans);
}
*/

int main(void)
{
    int i, j, k;
    int n;
    int div[10001];
    static int dp[2][5001][2];
    
    scanf("%d", &n);
    
    for (i = 1; i <= n - 1; i++){
        scanf("%d", &div[i]);
    }
    
    for (i = 0; i < 2; i++){
        for (j = 0; j <= n / 2; j++){
            dp[i][j][0] = dp[i][j][1] = INF;
        }
    }
    dp[0][0][0] = 0;
    
    for (i = 0; i <= n / 2; i++){
        for (j = 0; j <= n / 2; j++){
            if (i > 0){
                dp[i % 2][j][0] = dp[(i - 1) % 2][j][0];
                dp[i % 2][j][1] = dp[(i - 1) % 2][j][0] + div[i + j];
            }
            if (j > 0){
                dp[i % 2][j][0] = min(dp[i % 2][j][0], dp[i % 2][j - 1][1] + div[i + j]);
                dp[i % 2][j][1] = min(dp[i % 2][j][1], dp[i % 2][j - 1][1]);
            }
        }
    }
    
    printf("%d\n", min(dp[n % 2][n / 2][0], dp[n % 2][n / 2][1]));
    
    return (0);
}