CODE FESTIVAL 2017 qual B: D - 101 to 010
感想
解けず。連続する1
を数えて数列に変形するのは必須だと思ってその方向ばかり考えていたが、そうだとすると実装が面倒になりすぎるので完全に失敗だった。
solution
連鎖的に操作をするとき111...11101
あるいは10111...111
の形を000...00010
などにできる。
そのようなものだけ見ればよいので、111...11101
と10111...111
の形の部分文字列を関係としてDP。
愚直にやると$O(N^2)$だが、形が制限されているので前回の端を覚えておくなどすれば$O(N)$。
implementation
#include <algorithm>
#include <iostream>
#include <vector>
#define repeat_reverse(i, n) for (int i = (n)-1; (i) >= 0; --(i))
#define whole(x) begin(x), end(x)
using namespace std;
template <class T> inline void setmax(T & a, T const & b) { a = max(a, b); }
int solve(int n, string const & s) {
vector<int> dp(n + 1);
int r = n;
repeat_reverse (l, n) {
dp[l] = dp[l + 1];
if (l + 2 < n and s[l + 2] == '0') {
r = l + 2;
}
if (s[l] == '1') {
if (s[l + 1] == '0') {
if (s[r - 1] == '1') {
setmax(dp[l], dp[r] + r - l - 2);
if (s[r - 2] == '1') {
setmax(dp[l], dp[r - 1] + (r - 1) - l - 2);
}
}
} else {
if (r + 1 < n and s[r + 1] == '1') {
setmax(dp[l], dp[r + 2] + (r + 2) - l - 2);
}
}
}
}
return *max_element(whole(dp));
}
int main() {
int n; string s; cin >> n >> s;
cout << solve(n, s) << endl;
return 0;
}