二分探索すれば楽できることをすぐに思いつけてよかった。
問題概要
o
と x
のみからなる長さ の文字列
が与えられる。
文字列 を
回繰り返して得られる文字列
を考える。この文字列
に対して、最大
回まで、
x
を o
に書き換える操作を行うことができる。
書き換えた後の、o
が連続する部分文字列の長さとして、考えられる最大値を求めよ。
制約
考えたこと
文字列 上の区間
であって、その区間内の
x
の個数が 個以下であるときの、
の最大値を求める問題と言える。
を固定して考えることにした。ここで、
の場合のみ考えれば十分である。
を固定すると、次のような問題と言える。
文字列 の区間
内の
x
の個数が 個以下となるような最大の
を求めよ
これは二分探索法によって の計算量で求められる。
よって、全体として の計算量で解ける。
AC したコード
#include <bits/stdc++.h> using namespace std; int main() { long long N, M, K; string S; cin >> N >> M >> K >> S; // S の中の x の個数を高速に求めるための累積和 vector<long long> sum(N + 1, 0); for (int i = 0; i < N; ++i) sum[i+1] = sum[i] + (S[i] == 'x'); // T の len 文字目から考えるか場合を全探索 (len = 0, 1, ..., N-1) long long res = 1; for (int len = 0; len < N; ++len) { // T の [len, len+x) 中の x の個数が K 個以下となる最大の x を求める long long left = -1, right = N * M - len + 1; while (right - left > 1) { long long x = (left + right) / 2; long long kurikaeshi = (x + len) / N; long long amari = (x + len) % N; long long num = sum.back() * kurikaeshi + sum[amari] - sum[len]; if (num <= K) left = x; else right = x; } res = max(res, left); } cout << res << endl; }