[AtCoder] ABC 009 C – 辞書式順序ふたたび
問題
方針
\( T_i \) の先頭から貪欲に辞書順の最小の文字から構成できるかを調べます。これは文字の頻度を管理することで、高速に計算することができます。文字列 \( S \) の \( i \) 文字目から \( j \) 文字目までの部分文字列を \( S(i, j) \) とします。
\( T(1, i) \) までの部分文字列を決めた時、\( S(1, i ) \) と異なる文字の数は愚直に計算できます。このとき、\( T(i + 1, N) \) と \( S(i + 1, N) \) の異なる文字の数の最小値は、文字の頻度を比べることで求めることができます。
コード
#include <bits/stdc++.h> using namespace std; typedef long long ll; int diff(int *a, int *b) { int ret = 0; for (int i = 0; i < 26; i++) { ret += max(0, a[i] - b[i]); } return ret; } int main() { int N, K; string S; cin >> N >> K >> S; if (K == 0 || K == 1) { cout << S << "\n"; return 0; } int a[26]{}, b[26]{}; for (int i = 0; i < N; i++) { a[S[i] - 'a']++; b[S[i] - 'a']++; } string T(N, '?'); int d = 0; for (int i = 0; i < N; i++) { a[S[i] - 'a']--; if (d == K) { T[i] = S[i]; continue; } for (int j = 0; j < 26; j++) { if (b[j] == 0) continue; if (S[i] - 'a' == j) { b[j]--; T[i] = S[i]; break; } // T_i = j とできるか? b[j]--; if (d + 1 + diff(a, b) <= K) { d++; T[i] = (char)(j + 'a'); break; } b[j]++; } } cout << T << "\n"; return 0; }
ディスカッション
コメント一覧
まだ、コメントがありません