POJ-1990 MooFest
题意:
每头牛
i
i
i 都有自己的位置
x
i
x_i
xi 和听力上限
v
i
v_i
vi ,如果 两头牛
i
i
i 和
j
j
j 想要交流,假设
x
i
<
x
j
x_i<x_j
xi<xj ,需消耗
(
x
j
−
x
i
)
×
m
a
x
(
v
i
,
v
j
)
(x_j-x_i) \times max(v_i,v_j)
(xj−xi)×max(vi,vj) 这些能量。计算任意两头牛交流需要消耗的能量总和,共
N
(
N
−
1
)
/
2
N(N-1)/2
N(N−1)/2 对。
思路:
这个题与之前写的一个题是一样的做法(点击查看题解),只不过这个加了一个
m
a
x
(
v
i
,
v
j
)
max(v_i,v_j)
max(vi,vj) ,那我们就先按照
v
v
v 从小到大排序,这样
v
v
v 的大小就没影响了。
我们假设一根数轴
x
x
x 轴,用数组
c
c
c 维护已经放在
x
x
x 轴上的点的个数,数组
c
x
cx
cx 维护已经放在数轴上的点的坐标和,然后乱搞一下就计算出总的距离差,然后再乘上
v
i
vi
vi 。因为已经排序了,所以我们要放的这个牛的
v
i
v_i
vi 比前面的所有牛的
v
v
v 都要大,所以牛
i
i
i 与之前的任意一头牛交流
m
a
x
(
v
i
,
v
j
)
max(v_i,v_j)
max(vi,vj) 都等于
v
i
v_i
vi 。
Code:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 20005;
struct node {
int v, x;
} a[maxn];
bool cmp(node A, node B) { return A.v < B.v; }
ll c[maxn];
ll cx[maxn];
int lowbit(int x) { return x & (-x); }
void add1(int x) {
while (x < maxn) {
c[x] += 1;
x += lowbit(x);
}
}
void addx(int x, int val) {
while (x < maxn) {
cx[x] += val;
x += lowbit(x);
}
}
ll ask(int x) {
ll res = 0;
while (x > 0) {
res += c[x];
x -= lowbit(x);
}
return res;
}
ll askx(int x) {
ll res = 0;
while (x > 0) {
res += cx[x];
x -= lowbit(x);
}
return res;
}
int main() {
#ifdef LOCAL_LIUZHIHAN
freopen("in.in", "r", stdin);
// freopen("out.out", "w", stdout);
#endif
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d%d", &a[i].v, &a[i].x);
sort(a + 1, a + n + 1, cmp);
ll ans = 0;
for (int i = 1; i <= n; i++) {
ll cnt_front = ask(a[i].x);
ll cnt_back = i - 1 - cnt_front;
ll sum_front = askx(a[i].x);
ll sum_all = askx(20002);
ans += (cnt_front * a[i].x - sum_front + sum_all - sum_front - cnt_back * a[i].x) * a[i].v;
add1(a[i].x);
addx(a[i].x, a[i].x);
}
printf("%lld\n", ans);
return 0;
}