読者です 読者をやめる 読者になる 読者になる

Lilliput Steps

小さな一歩から着実に. 数学やプログラミングのことを書きます.

PKU 1990 - MooFest

問題文 : MooFest

解法 :
2匹の牛について、離れている距離*Max(牛iの聴力, 牛jの聴力)が必要な声のレベルなので、
(全ての声の大きさの総和) = 最も聴力が必要な牛 * 離れている距離の総和 + 次に聴力が必要な牛 * 離れている距離の総和 + ... となる.

ゆえに, 聴力の閾値を降順でソートし, 総和をBITで求めてやれば良い.
ここで, 牛iがいる位置xiと他の点との位置関係は, xi > xjまたはxi < xjとなるので, それを考慮してBITを構築する.

具体的には, BITを配列のように使用し, xi未満の点の総和とxi以上の点の総和をO(log(Max(xi)))時間で求められるようにすればよい.

以上の方法で総和を求めれば, O(Nlog(Max(xi)))時間でこの問題を解く事が出来る.

コード :

#include <cstdio>
#include <algorithm>

using namespace std;

typedef long long lint;
int n;

lint c[20001], d[20001];

lint sum(lint *bit, int k)
{
	lint res = 0;
	while (k > 0){
		res += bit[k];
		k -= k & -k;
	}
	
	return (res);
}

void add(lint *bit, int k, lint x)
{
	while (k <= 20001){
		bit[k] += x;
		k += k & -k;
	}
}

int main()
{
	pair<int, int> cow[20000];
	int ma = 0;
	scanf("%d", &n);
	
	for (int i = 0; i < n; i++){
		scanf("%d %d", &cow[i].first, &cow[i].second);
		ma = max(cow[i].second, ma);
	}
	
	for (int i = 0; i < n; i++){
		add(c, cow[i].second, 1);
		add(d, cow[i].second, cow[i].second);
	}
	
	sort(cow, cow + n);
	reverse(cow, cow + n);
	
	lint ans = 0;
	
	for (int i = 0; i < n; i++){
		add(d, cow[i].second, -cow[i].second);
		add(c, cow[i].second, -1);
		lint bigNum = sum(c, ma) - sum(c, cow[i].second - 1), bigVal = sum(d, ma) - sum(d, cow[i].second - 1);
		lint smlNum = sum(c, cow[i].second - 1), smlVal = sum(d, cow[i].second - 1);
		ans += cow[i].first * ((smlNum * cow[i].second - smlVal) + (bigVal - bigNum * cow[i].second));
	}
	
	printf("%lld\n", ans);
	
	return (0);
}