CODE FESTIVAL 2015 朝プロ D - ヘイホー君と削除

,

そこそこの速度でAC。でもDPの周りで実装ミスして1WA。

D - ヘイホー君と削除

問題

長さ$N$の文字列$S$が与えられる。文字列$S$中の文字をひとつ選んで削除するという操作を行うことができる。 この$S$から、なんらかの文字列$T$の2回の繰り返しで表現されるような文字列$T \oplus T$を作りたい。必要な最小の操作の回数を答えよ。

解法

文字列$S$を文字列$T_1$と$T_2$に分割し、それぞれの部分列で一致するものを探す、という手順を取る。$T_2$の開始位置に関して総当たりする。$T_1$と$T_2$それぞれからいくつ文字を使ったかをindexに、一致する部分列で最長のものの長さを値とするDPを行う。$O(N^3)$。

実装

DP tableの更新の向きを間違えてWA。tableをひとつしか持たない場合、indexの大きい側から更新していく必要がある。最近よくやるミスなので気を付けたい。

#include <iostream>
#include <vector>
#define repeat_from(i,m,n) for (int i = (m); (i) < (n); ++(i))
using namespace std;
int main() {
    int n; string s; cin >> n >> s;
    int usable = 0;
    repeat_from (l, 1, n) {
        vector<vector<int> > dp(l+1, vector<int>(n-l+1));
        repeat_from (i, 1, l+1) {
            repeat_from (j, 1, n-l+1) {
                dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
                if (s[i-1] == s[l+j-1]) dp[i][j] = max(dp[i][j], dp[i-1][j-1]+1);
            }
        }
        usable = max(usable, dp[l][n-l]);
    }
    cout << n - 2*usable << endl;
    return 0;
}