公式

G - Ghost Ants 解説 by MtSaka


条件を整理すると、 \(1\) 以上 \(N\) 以下の整数 \(i,j(i \neq j)\)\(S_i=\) 1 かつ \(S_j=\) 0 かつ \( 0 < X_j-X_i \leq 2 \times T\) を満たすとき、蟻 \(i\) と蟻 \(j\) はすれ違います。 このような \((i,j)\) の組の個数を求める必要があります。

\(X\) を昇順に並び替え、同時に対応する \(S\) も並び替えても答えは変わらないため、並び替えたとします。\(S_i=\) 1 である \(i\)\(X_i\) を取り出した列を \(A\) とし、\(S_i=\) 0である \(i\)\(X_i\) を取り出した列を \(B\) とします。 このとき、\(A\)\(B\) も昇順とします。

ある \(i\) に対して \(B_j > A_i\) なる\(j\) の最小値は \(i\) が増加するにつれて単調に増加します。また、同時に\(B_j-A_i \leq 2 \times T\) を満たす \(j\) の最大値も \(i\) が増加するにつれて単調に増加します。以上から尺取り法を用いることで、各 \(i\) に対して条件を満たす \(j\) の数を求めることができます。そして、これらの総和を求めることで答えを得られます。

実装例(C++):

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

int main() {
    int n;
    ll t;
    cin >> n >> t;
    string s;
    cin >> s;
    vector<ll> x1, x2;
    for (int i = 0; i < n; ++i) {
        ll x;
        cin >> x;
        if (s[i] == '1')
            x1.push_back(x);
        else
            x2.push_back(x);
    }
    sort(x1.begin(), x1.end());
    sort(x2.begin(), x2.end());
    int l = 0, r = 0;
    ll ans = 0;
    for (int i = 0; i < (int)x1.size(); ++i) {
        while (l < (int)x2.size() && x2[l] < x1[i]) l++;
        while (r < (int)x2.size() && x2[r] <= x1[i] + 2 * t) r++;
        ans += r - l;
    }
    cout << ans << '\n';
}

投稿日時:
最終更新: