【AtCoder】ABC 360 D - Ghost Ants | 茶コーダーが解くAtCoder (original) (raw)

atcoder.jp

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

問題概要

数直線上に  N 匹の蟻がおり、蟻  i は始め相異なる座標  X_i にいて正負どちらかの方向を向いている。蟻が向いている向きは0 (負方向) , 1 (正方向) からなる長さ  N の文字列  S で与えられる。現在を時刻  0 とし、時刻  T + 0.1 まで全ての蟻が各々の向いている方向に単位時間あたり  1 の速さで動く。時間  T + 0.1 の間に蟻  i j がすれ違う整数組  (i, j) \: (1 \leq i \lt j \leq N) の個数を求めよ。

制約

考察

正方向を向いている蟻に注目し、時間  T + 0.1 の間に負方向を向いた蟻と何匹すれ違うかを考えよう。

ここで、単位時間あたりに正方向を向いた蟻と負方向を向いた蟻の距離は  2 縮まることから、負方向を向いた蟻を数直線上に固定して、正方向を向いた蟻を単位時間あたり  2 の速さで移動させても状況は変わらない。

したがって、正方向を向いた各蟻について、その蟻の位置から正方向に  2(T+0.1) までの範囲内にいる負方向を向いた蟻の数を数えて、それを足し合わせれば答えが求められることになる。

さて、この蟻の数を数えるにあたって、愚直にループを用いると各蟻に対して  O(N) かかってしまい実行時間制限に間に合わない。そこで、負方向を向いた蟻の位置をソートしておくことで、二分探索により対数時間まで計算量を抑えることができる。

コード

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

#define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++)

using ll = long long;

int main() { int N, T; cin >> N >> T; string S; cin >> S; vector left, right; rep(i, 0, N) { ll x; cin >> x; if (S[i] == '0') { left.push_back(x); } else { right.push_back(x); } }

sort(all(left));

ll ans = 0;
for (auto &&x : right)
{
    ans += upper_bound(all(left), x + 2 * (T + 0.1)) - lower_bound(all(left), x);
}

cout << ans << endl;

}

atcoder.jp

実装時間: 20分

本当に灰Diffなのかこの問題?