公式
D - ほぼ同じ信号パターン / Nearly Identical Signal Patterns 解説
by
D - ほぼ同じ信号パターン / Nearly Identical Signal Patterns 解説
by
MMNMM
数えるべき \((l _ 1,r _ 1),(l _ 2,r _ 2)\ (l _ 1\le l _ 2)\) の組について、\(d\coloneqq l _ 2-l _ 1\) の値を固定して考えます。 \(d\) は \(1\) 以上 \(N-1\) 以下の整数になります。
\(f _ i\coloneqq\bigl(s _ i\ne s _ {i+d}\) なら \(1\) 、そうでなければ \(0\bigr)\) として \(f _ 1,f _ 2,\ldots,f _ {N-d}\) を定めます。 すると、\((l _ 1,r _ 1),(l _ 1+d,r _ 1+d)\) が条件を満たすことは、\(\displaystyle\sum _ {i=l _ 1} ^ {r _ 1}f _ i=1\) であることと同値です。
\(f _ i=1\) であるような \(i\) を求めておくことで、このような区間 \((l _ 1,r _ 1)\) を数え上げることができます。
時間計算量は \(O(N ^ 2)\) となります。
実装例は以下のようになります。
#include <iostream>
#include <vector>
#include <print>
int main() {
using namespace std;
int N;
string S;
cin >> N >> S;
long ans = 0;
for (int d = 1; d < N; ++d) { // ありえる d ごとに
vector<int> diff_index; // f_i = 1 となる i を求める
diff_index.emplace_back(); // 番兵を置いておく
for (int i = 0; i + d < N; ++i)
if (S[i] != S[i + d])
diff_index.emplace_back(i + 1);
diff_index.emplace_back(N - d + 1); // 番兵を置いておく
int M = diff_index.size();
for (int i = 0; i + 2 < M; ++i) {
ans += (diff_index[i + 2] - diff_index[i + 1]) * (diff_index[i + 1] - diff_index[i]); // i 番目の 1 から隣の 1 まで左右に独立に伸ばせる
}
}
cout << ans << endl;
return 0;
}
N = int(input())
S = input()
ans = 0
for d in range(1, N): # ありえる d ごとに
diff_index = [] # f_i = 1 となる i を求める
for i in range(N - d):
if S[i] != S[i + d]:
diff_index.append(i + 1)
diff_index = [0] + diff_index + [N - d + 1] # 番兵を置いておく
for i in range(len(diff_index) - 2):
ans += (diff_index[i + 2] - diff_index[i + 1]) * (diff_index[i + 1] - diff_index[i]) # i 番目の 1 から隣の 1 まで左右に独立に伸ばせる
print(ans)
投稿日時:
最終更新:
