【AtCoder】ABC 480 D - Concatenation of Prefixes
AtCoder/ABC/D問題AtCoder/ABC/400点問題AtCoder/緑DiffAtCoder/NoviSteps/1QAtCoder/累積和AtCoder/二分探索/lower_bound競技プログラミング

D - Concatenation of Prefixes
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
AtCoder
実行時間制限: 2 sec / メモリ制限: 1024 MiB / Difficulty: 864 / NoviSteps: 1Q / 配点: 400 点
問題概要
長さ の整数列 が与えられる。
以下の手順で長さ の数列 を作る。
- 最初、 を空列とする。
- の順に、 の末尾に を連結する。
以下の形式のクエリが 個与えられるので、それぞれ処理せよ。
- が与えられる。 を求めよ。
制約
- 各クエリにおいて、
- 入力は全て整数
考察
とすると、 である。
このとき、 の末尾の項は の 番目に現れる。 これを とおく。
いま、 とおけば( の累積和)、各クエリでは を計算すればよい。
が に含まれる要素であるとすると、 と定義できるから、これは二分探索で求めることができる。
すると、 より前にある要素の個数は 個なので、 の中での位置は と表せる。
したがって、
- ( の累積和)
- ( の累積和)
を定義すれば、
と表すことができる。
計算量は、累積和の計算に 、各クエリに対して二分探索を行うので となり、全体で となる。
実装例
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, Q;14. cin >> N >> Q;15. vector<ll> A(N);16. rep(i, 0, N) cin >> A[i];17. 18. vector<ll> S(N + 1, 0), T(N + 1, 0), C(N + 1, 0);19. rep(i, 0, N)20. {21. S[i + 1] = S[i] + A[i];22. T[i + 1] = T[i] + S[i + 1];23. C[i + 1] = C[i] + (i + 1);24. }25. 26. auto f = [&](ll x) -> ll {27. if (x == 0) return 0;28. 29. int k = lower_bound(all(C), x) - C.begin();30. return T[k - 1] + S[x - C[k - 1]];31. };32. 33. while (Q--)34. {35. ll L, R;36. cin >> L >> R;37. 38. cout << f(R) - f(L - 1) << endl;39. }40. 41. return 0;42.}https://atcoder.jp/contests/abc480/submissions/80170230
atcoder.jp
実装時間: 30分
コメント
累積和が大量に出てくるので、気を付けないと添え字ガチャに苦しむことになる。





