第3回 ドワンゴからの挑戦状 本選: A - 計算ドリル

,

http://dwacon2017-honsen.contest.atcoder.jp/tasks/dwango2017final_a

solution

区間DP。 文字を置き換えてもよいという制約の付いた、文脈自由文法の構文解析と認識すればよい。 区間$[l,r)$に対し$k$文字書き換えたときの最大値/最小値を値$\mathrm{dp}_{\max}(l,r,k), \mathrm{dp}_{\min}(l,r,k)$とする。 $O({|S|}^5)$で通る。 $2$分木になっているのでloopの範囲を丁寧にすれば$O({|S|}^4)$に落ちる。

implementation

#include <iostream>
#include <vector>
#define repeat(i,n) for (int i = 0; (i) < int(n); ++(i))
#define repeat_from(i,m,n) for (int i = (m); (i) < int(n); ++(i))
using namespace std;
template <class T> void setmax(T & a, T const & b) { if (a < b) a = b; }
template <class T> void setmin(T & a, T const & b) { if (b < a) a = b; }
template <typename X, typename T> auto vectors(X x, T a) { return vector<T>(x, a); }
template <typename X, typename Y, typename Z, typename... Zs> auto vectors(X x, Y y, Z z, Zs... zs) { auto cont = vectors(y, z, zs...); return vector<decltype(cont)>(x, cont); }
const int inf = 1e9+7;
int solve(int k, string s) {
    int n = s.length();
    auto dp_max = vectors<int>(n, n+1, k+1, - inf);
    auto dp_min = vectors<int>(n, n+1, k+1, + inf);
    repeat (i,n) if (isdigit(s[i])) {
        dp_max[i][i+1][0] = s[i] - '0';
        dp_min[i][i+1][0] = s[i] - '0';
    }
    repeat (i,n) {
        if (k) {
            dp_max[i][i+1][1] = 9;
            dp_min[i][i+1][1] = 0;
        }
    }
    repeat (len,n+3) repeat (l,n-len+3) {
        int r = l + len;
        if (r <= n+1) {
            repeat_from (m,l+1,r+3) if (m-l >= 1 and r-1-m >= 1 and r-1 < n) {
                repeat (i,k+3) repeat (j,k+3) {
                    if (i+j <= k) {
                        if (s[r-1] == '+') {
                            if (dp_max[l][m][i] != - inf and dp_max[m][r-1][j] != - inf) setmax(dp_max[l][r][i+j], dp_max[l][m][i] + dp_max[m][r-1][j]);
                            if (dp_min[l][m][i] != + inf and dp_min[m][r-1][j] != + inf) setmin(dp_min[l][r][i+j], dp_min[l][m][i] + dp_min[m][r-1][j]);
                        }
                        if (s[r-1] == '-') {
                            if (dp_max[l][m][i] != - inf and dp_min[m][r-1][j] != + inf) setmax(dp_max[l][r][i+j], dp_max[l][m][i] - dp_min[m][r-1][j]);
                            if (dp_min[l][m][i] != + inf and dp_max[m][r-1][j] != - inf) setmin(dp_min[l][r][i+j], dp_min[l][m][i] - dp_max[m][r-1][j]);
                        }
                    }
                    if (i+j+1 <= k) {
                        if (dp_max[l][m][i] != - inf and dp_max[m][r-1][j] != - inf) setmax(dp_max[l][r][i+j+1], dp_max[l][m][i] + dp_max[m][r-1][j]);
                        if (dp_min[l][m][i] != + inf and dp_min[m][r-1][j] != + inf) setmin(dp_min[l][r][i+j+1], dp_min[l][m][i] + dp_min[m][r-1][j]);
                        if (dp_max[l][m][i] != - inf and dp_min[m][r-1][j] != + inf) setmax(dp_max[l][r][i+j+1], dp_max[l][m][i] - dp_min[m][r-1][j]);
                        if (dp_min[l][m][i] != + inf and dp_max[m][r-1][j] != - inf) setmin(dp_min[l][r][i+j+1], dp_min[l][m][i] - dp_max[m][r-1][j]);
                    }
                }
            }
        }
    }
    return dp_max[0][n][k];
}
int main() {
    int k; string s; cin >> k >> s;
    int ans = solve(k, s);
    if (ans == - inf) {
        cout << "NG" << endl;
    } else {
        cout << "OK" << endl;
        cout << ans << endl;
    }
    return 0;
}