実行時間制限: 2 sec / メモリ制限: 1024 MB / Difficulty: 658
問題概要
英大文字からなる文字列 が与えられる。整数の組 であって、以下の条件をともに満たすものの個数を求めよ。
- をこの順に結合して得られる長さ3の文字列が回文となる。
制約
- の長さは 以上 以下。
考察
条件2が満たされるためには、 が成り立てば十分。つまり、 は任意に決められるということだ。
したがって、 の範囲で を走査し、各 について かつ を満たす整数組 を数え上げることを考える。
これを実現するためのデータ構造を考えよう。ここでは、以下の2つの配列を用意する。
なお、 はアルファベット26文字に対応している。構築方法は以下の通り。
- について、
- ならば、 について、 を 増やす。
- そうでないとき、
- とする。
- を 増やし、 を 減らす。これは を1増やすことによってずれた文字の分を考慮している。
ここまで分かれば、あとは答えを求めるだけ。アルファベット26文字の集合を とすると、最終的な答えは、
となる。
なお、以下のコードでは 0-indexed としている。
コード
#include <bits/stdc++.h> using namespace std; using ll = long long; #define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++) // ======================================== // int main() { string S; cin >> S; int l = S.size(); vector<vector<ll>> front(l, vector<ll>(26, 0)); vector<vector<ll>> back(l, vector<ll>(26, 0)); rep(i, 0, l) { if (i == 0) { rep(j, 1, l) { back[0][S[j] - 'A']++; } continue; } rep(j, 0, 26) { front[i][j] = front[i - 1][j]; back[i][j] = back[i - 1][j]; } front[i][S[i - 1] - 'A']++; back[i][S[i] - 'A']--; } ll ans = 0; rep(j, 1, l - 1) { rep(ch, 0, 26) { ans += front[j][ch] * back[j][ch]; } } cout << ans << endl; }
実装時間: 30分
ちなみに、 と は実は1つにまとめることができて、累積和を用いながらこの問題を解くこともできる。これが公式解説の解法1に対応する。
また、3つの要素があって真ん中を固定して考えるというのは典型らしい。 ARC084-C などが類題。