問題
ある文字列Sが与えられる。Sに含まれる部分文字列のうち出現頻度が最も高いものの長さを求めよ
例
- 入力: ababab
- 出力: 6
これにはabが6個入っているので出力は6となっている。
解説
参考: 题解 Codeforces Round #621 (Div. 1 + Div. 2) (CF1307) - kylin_xy - 博客园
こちらの中国の方が書かれた解説を読んで通した。DPに苦手意識がまだある…
上の記事ではなぜ通るのかがあまり解説されていなかったので、なぜ通るか以下に書き下しておく。
DPで解く
この問題はxy
あるいはx
が最も出現頻度が高くなる(x、yはそれぞれ任意の文字でx != y)。たとえばabcacbac
ならac
が最も出現頻度が高い。
まず、同じ文字が2回以上現れない理由は簡単であろう。なぜならxxy
にはxy
が2回含まれているため、xxy
よりxy
のほうが出現頻度が高くなる。
そして、xyz
を考えなくて良いかも同様にわかる。xyz
にはxy
が含まれるのだから、仮にxyz
が最も出現頻度が高いとしたら、xy
も同じ頻度で現れている。今回の問題は出現頻度さえわかれば良いので、xy
だけ着目すればよい。
以上がわかればあとはDPを書くだけとなる。
#include <iostream> #include <vector> using namespace std; using ll = long long; using vi = vector<ll>; template<class T>using vv = vector<vector<T>>; #define in(v) v; cin >> v; #define rep(i,n) for(int i=0;i<(n);++i) int main() { string in(S); int N = S.size(); vv<ll> dp(26, vi(26, 0)); // dp[a][b] = abの出現頻度 vi count(26, 0); rep(i, N) { rep(j, 26) dp[j][S[i]-'a'] += count[j]; // ここまでにjが出た回数ぶん更にふえる ++count[S[i]-'a']; } ll ans = 0; rep(i, 26) rep(j, 26) ans =max(ans, max(dp[i][j], count[i])); cout << ans << endl; return 0; }