公式

C - Comfortable Distance 解説 by cn449


\(j\) を固定して答えを数え上げることを考えます。\(j - R \leq i \leq j - L\) かつ \(S_i = S_j\) を満たす \(i\) の個数が求まればよいです。これは、各英小文字について出現頻度の回数の累積和を前計算しておくと求めることができます。具体的には、\(A_{c, k}\)\(1,2,\ldots, k\) 文字目の英小文字 \(c\) の出現回数とすると、求めるべき \(i\) の個数は \(A_{S_j, \max(j - L,0)} - A_{S_j, \max(j - R - 1,0)}\) となります。

上の解法は文字種を \(\sigma\) として \(O(\sigma N)\) 時間になりますが、\(O(\sigma + N)\) 時間で解くこともできます。常に \(j - R \leq i \leq j - L\) の範囲での \(S_i\) の頻度配列を管理しておき、\(j = 1, 2, ..., N\) の順に差分更新しながら計算します。\(j\)\(1\) 増えたとき、集計するべき範囲の変化は \(O(1)\) です。したがって、頻度配列全体を持ちながら更新していくことで計算していくことができます。下の実装例も参考にしてください。

実装例(差分更新)

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int main() {
	int n, l, r;
	cin >> n >> l >> r;
	r++;
	string s;
	cin >> s;
	ll ans = 0;
	vector<int> cnt(26);
	for (int i = 0; i < n; i++) {
		if (i >= l) cnt[s[i - l] - 'a']++;
		if (i >= r) cnt[s[i - r] - 'a']--;
		ans += cnt[s[i] - 'a'];
	}
	cout << ans << '\n';
}

投稿日時:
最終更新: