解法. BIT
のため の愚直な全探索では間に合わないのでより高速な解法が必要となる.
閾値で昇順にソートした牛の列を とする.すなわち, ならば とする.また, とする.ここで, と との間で必要な音量は,
となる.よって, と 間の音量の総和は,
となるので,各 で が高速に計算出来れば嬉しい.
を次のように2つに分割する.
このとき, と 間の距離の総和は次のようになる.
Binary Indexed Tree (BIT) [1] を2つ用いると上の式を 時間で計算することができる. と を求めるBITの要素 の値は距離 の牛が登録されていれば1,されていなければ0とする.次に, と を求めるBITの要素 の値は距離 にいる牛の閾値とする.
計算時間: ()
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<class T>
struct BinaryIndexedTree {
private:
vector<T> bit;
int size;
public:
BinaryIndexedTree(int num) : bit(num + 1, 0), size(num) {}
T Sum(int a) {
T ret = 0;
for (int x = a; x > 0; x -= x & -x) ret += bit[x];
return ret;
}
T Sum(const int l, const int r) { return Sum(r) - Sum(l - 1); }
void Add(int a, int w) {
for (int x = a; x <= size; x += x & -x) bit[x] += w;
}
};
int main() {
cin.tie(0);
ios::sync_with_stdio(false);
int n, max_x = 0;
cin >> n;
vector<pair<int, int> > cow(n);
for (int i = 0; i < n; ++i) {
cin >> cow[i].first >> cow[i].second;
max_x = max(max_x, cow[i].second);
}
sort(cow.begin(), cow.end());
long long sum = 0;
BinaryIndexedTree<int> bit_num(max_x);
BinaryIndexedTree<long long> bit_x(max_x);
for (int i = 0; i < n; ++i) {
const long long x = cow[i].second, v = cow[i].first;
sum += v * ((bit_num.Sum(0, x) * x - bit_x.Sum(0, x)) + (bit_x.Sum(x, max_x) - bit_num.Sum(x, max_x) * x));
bit_num.Add(x, 1);
bit_x.Add(x, x);
}
cout << sum << endl;
return 0;
}
まとめ
この問題を2次元のユークリッド距離に拡張したら 時間で出来るのか某工房で話題に上がったのですがどうなのでしょう.