CODE FESTIVAL 2015 あさプロ Middle B - ヘイホー君と削除
解法
文字列を2つに分断して最長共通部分文字列(LCS:Longest Common Substring)を求めると操作回数も分かる。
入力例1の場合なら
"","abacbabc" -> ""
"a","bacbabc" -> "a"
"ab","acbabc" -> "ab"
"aba","cbabc" -> "ba"
"abac","babc" -> "bac"
"abacb","abc" -> "abc"
"abacba","bc" -> "bc"
"abacbab","c" -> "c"
LCSを残してそれ以外を削除すれば平方を作ることができる。最長共通部分文字列を残しているのだから、これ以上長い文字列を残すことはできない。この例の場合は"bacbac"か"abcabc"を残すのが最適。
ちなみにLCSは動的計画法で求めることができる(蟻本参照)。
#include <bits/stdc++.h> #define GET_MACRO(a, b, c, NAME, ...) NAME #define rep(...) GET_MACRO(__VA_ARGS__, rep3, rep2)(__VA_ARGS__) #define rep2(i, a) rep3 (i, 0, a) #define rep3(i, a, b) for (int i = (a); i < (b); i++) #define repr(...) GET_MACRO(__VA_ARGS__, repr3, repr2)(__VA_ARGS__) #define repr2(i, a) repr3 (i, 0, a) #define repr3(i, a, b) for (int i = (b) - 1; i >= (a); i--) #define chmin(a, b) ((b) < a && (a = (b), true)) #define chmax(a, b) (a < (b) && (a = (b), true)) using namespace std; typedef long long ll; int lcs(string s, string t) { int m = s.length(); int n = t.length(); vector<vector<int>> dp(m + 1, vector<int>(n + 1)); rep (i, m) rep (j, n) { if (s[i] == t[j]) { dp[i + 1][j + 1] = dp[i][j] + 1; } else { dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]); } } return dp[m][n]; } int main() { int n; cin >> n; string s; cin >> s; int ans = 1e9; rep (i, s.length()) { int l = lcs(s.substr(0, i), s.substr(i)); chmin(ans, n - l * 2); } cout << ans << endl; }
感想
ライブラリにLCS入れておくべきだった。