【AtCoder】ABC 449 C - Comfortable Distance

C - Comfortable Distanceatcoder.jp favicon

実行時間制限: 2 sec / メモリ制限: 1024 MiB / Difficulty: 330 / NoviSteps: ??? / 配点: 300 点

問題概要

英小文字からなる長さ NN の文字列 SS が与えられるので、整数の組 (i,j)(i, j) であって、以下の条件をすべて満たすものの個数を求めよ。

  • 1ijN1 \leq i \leq j \leq N
  • Si=SjS_i = S_j
  • LjiRL \leq j - i \leq R

制約

  • 2N5×1052 \leq N \leq 5 \times 10^5
  • 1LRN11 \leq L \leq R \leq N - 1
  • N,L,RN, L, R は整数

考察

各アルファベットについて、 SS での出現位置(インデックス)をそれぞれ小さい順に頻度配列として記録していく。

その上で、SSii 文字目に注目したとき、 jj として見るべき範囲は、条件の第3式を変形して

LjiR    i+Lji+RL \leq j - i \leq R \iff i + L \leq j \leq i + R

となる。

頻度配列の SiS_i の要素は昇順ソートされた状態となっているはずだから、二分探索で i+Li + L 以上 i+Ri + R 以下のものがいくつあるかを数え、それを全ての ii について合計すればよい。

計算量は全体で O(NlogN)O(N \log N) となる。

実装例

CPP
1.#include <bits/stdc++.h>
2.using namespace std;
3.
4.#define all(x) (x).begin(), (x).end()
5.#define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++)
6.
7.using ll = long long;
8.
9.// ======================================== //
10.
11.int main()
12.{
13. int N, L, R;
14. string S;
15. cin >> N >> L >> R >> S;
16.
17. vector<vector<int>> pos(26);
18. rep(i, 0, N)
19. {
20. pos[S[i] - 'a'].push_back(i);
21. }
22.
23. ll ans = 0;
24. rep(i, 0, N)
25. {
26. int c = S[i] - 'a';
27.
28. int l = i + L;
29. int r = i + R;
30.
31. auto itr_l = lower_bound(all(pos[c]), l);
32. auto itr_r = upper_bound(all(pos[c]), r);
33.
34. ans += (itr_r - itr_l);
35. }
36.
37. cout << ans << endl;
38.
39. return 0;
40.}
Submission #74141581 - AtCoder Beginner Contest 449atcoder.jp favicon

実装時間: 5 分

コメント

今考えると、尺取り法のようにして O(N)O(N) の計算量で解くやり方の方が楽だったかもしれない。