Quantcast
Channel: プログラミング
Viewing all articles
Browse latest Browse all 8686

【AtCoder】ABC 371 D - 1D Country | 茶コーダーが解くAtCoder - Yuulis.log

$
0
0

atcoder.jp

実行時間制限: 2 sec / メモリ制限: 1024 MB / Difficulty: 408

問題概要

数直線上に  N個の村がある。  i番目の村は座標  X_iにあって、人口は  P_i人である。次の形式で与えられる  Q個のクエリに答えよ。

  • クエリ : 整数  L_i, R_iが与えられるので、座標  L_i以上  R_i以下の村の人口の総和を求めよ。

制約

  • 入力は全て整数。
  •  1\leq N,Q\leq 2\times 10^5
  •  -10^9\leq X_1 \lt X_2 \lt \cdots \lt X_N \leq 10^9
  •  1\leq P_i\leq 10^9
  •  -10^9\leq L_i \leq R_i \leq 10^9

考察

クエリでは、配列のある区間における総和を聞かれているので、累積和を用いれば効率よく求められそう。


そこで、座標  L_i, R_i以下で最も座標が大きい村のそれぞれのインデックス  \mathrm{idx}_L, \mathrm{idx}_Rを求めたい。幸いなことに本問では  X_iが昇順ソートされた状態で与えられるので、この配列に対して二分探索をしてやることで対数時間で処理できる。

二分探索で求めたインデックスは累積和の計算時に開区間 [\mathrm{idx}_L, \mathrm{idx}_R)として使うので、  \mathrm{idx}_Rの方はupper_boundを用いることで、インデックスに  \pm 1をしないで済む。


以上で、計算量  O(Q \log N)アルゴリズムでこの問題を解くことができる。

コード

#include <bits/stdc++.h>usingnamespacestd;

using ll = longlong;

#define all(x) (x).begin(), (x).end()#define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++)// ======================================== //intmain()
{
    int N;
    cin>> N;
    vector<int> X(N);
    rep(i, 0, N) cin>> X[i];
    vector<ll> P(N);
    rep(i, 0, N) cin>> P[i];
    int Q;
    cin>> Q;

    vector<ll> ps(N + 1, 0);
    rep(i, 0, N) ps[i + 1] = ps[i] + P[i];

    while (Q--)
    {
        int L, R;
        cin>> L >> R;

        int idx_L = lower_bound(all(X), L) - X.begin();
        int idx_R = upper_bound(all(X), R) - X.begin();

        cout<< ps[idx_R] - ps[idx_L] << endl;
    }
}

atcoder.jp

実装時間: 25分


累積和と二分探索を組み合わせて解く良問。


Viewing all articles
Browse latest Browse all 8686

Latest Images

Trending Articles