集計処理の応用問題
問題概要
一般に、文字列 からいくつかの文字を抜き出して、それを並び替えることによって文字列
を作れるとき、
から
を作れるという。
英小文字からなる 個の文字列
が与えられる。
のいずれからも作れる文字列
のうち、最長のものを求めよ。複数考えられる場合は、そのうちの辞書順最小のものを求めよ。
制約
考えたこと
まずは、最長の長さを考えよう!
注目したいことは、各アルファベット文字ごとに独立に考えて良いということだ。つまり、
が文字 'a' を最大で何個含むことができるか
が文字 'b' を最大で何個含むことができるか
- ...
が文字 'z' を最大で何個含むことができるか
については、それぞれ独立に考えて良いのだ。そして、文字列 が含む文字 'a' の最大個数は
に含まれる 'a' の個数
に含まれる 'a' の個数
- ...
に含まれる 'a' の個数
の最小値を求めれば良い。
こうして、 の最長長さはわかった。最長である
のうち、辞書順最小のものを求めるためには、単純に文字 'a' を並べて、次の文字 'b' を並べて......とすればよい。
計算量は、 に含まれる各文字の個数をバケットを用いて集計することで、
(
はアルファベット文字の個数、
) と評価できる。
コード
#include <bits/stdc++.h> using namespace std; int main() { int N; cin >> N; vector<string> S(N); for (int i = 0; i < N; i++) cin >> S[i]; // S[0], ..., に a, b, ..., がそれぞれ何文字ずつあるかを計算する vector<vector<int>> nums(N, vector<int>(26, 0)); for (int i = 0; i < N; i++) { for (int j = 0; j < S[i].size(); j++) nums[i][S[i][j] - 'a']++; } // a, b, ... について、S[0], ..., 内部での登場回数の最小値を求める string res; for (int i = 0; i < 26; i++) { int mi = nums[0][i]; for (int j = 0; j < N; j++) mi = min(mi, nums[j][i]); res += string(mi, 'a' + i); } cout << res << endl; }