题目链接:https://codeforces.ml/contest/1311/problem/F
题意:在一维数轴上有n个点,每个点有一个速度,问这n个点在行驶过程中形成的最小的距离的和。
思路:啊啊啊啊啊啊!!读错题啦,卡了一天。这一题时间可以是小数!!!就是说,任意两个点,要么会在某一时刻相遇,要么永远也不会相遇,所以答案就是那些永远也不会相遇的点的起始位置差的绝对值的和。那怎么判断两个点会不会相遇呢?考虑初中物理公式,x =
x
i
+
v
i
{x}_{i} + {v}_{i}
xi+vi * t。任取两个点,联立方程组可得
t
=
x
2
−
x
1
v
1
−
v
2
t = \frac{x2 - x1}{v1 - v2}
t=v1−v2x2−x1要想t大于0,有两种情况
1、(x2 > x1 && v1 < v2);
2、(x2 < x1 && v1 > v2);
还有一种情况就是v1 == v2这时候他们永远不可能相遇,所以也算答案的一部分。
所以我们就可以考虑按照速度由小到大对结构体进行排序,之后每次扫到一个i,我们只需要统计前面有多少个数比a[i]小及其总和就好啦,这样我们可以维护两个树状数组,但是这一题数据范围有1e8,所以在加一个离散化就好。具体详见代码。
AC代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 2e5 + 7;
struct node {
LL x,y;
}a[maxn];
LL b[maxn];
bool cmp(node aa,node bb) {
if(aa.y == bb.y) return aa.x < bb.x;
else return aa.y < bb.y;
}
int n;
LL c1[maxn],c2[maxn];
int lowbit(int x) {
return x & (-x);
}
void update(LL x,LL y,LL c[]) {
for(int i = x ; i <= n ; i += lowbit(i)) {
c[i] += y;
}
}
LL query(LL x,LL c[]) {
LL ans = 0;
for(int i = x ; i > 0 ; i -= lowbit(i)) {
ans += c[i];
}
return ans;
}
int main() {
while(~scanf("%d",&n)) {
for(int i = 1 ; i <= n ; i++) {
scanf("%lld",&a[i].x);
b[i] = a[i].x;
}
for(int i = 1 ; i <= n ; i++) {
scanf("%lld",&a[i].y);
}
sort(b+1,b+n+1);
int pos = unique(b+1,b+n+1) - (b+1);
for(int i = 1 ; i <= n ; i++) {
a[i].x = lower_bound(b+1,b+pos+1,a[i].x) - b;
}
sort(a+1,a+n+1,cmp);
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
LL ans = 0;
for(int i = 1 ; i <= n ; i++) {
LL res1 = query(a[i].x,c1);///统计大小
LL res2 = query(a[i].x,c2);///统计个数
ans += res2 * b[a[i].x] - res1;///更新答案
update(a[i].x,b[a[i].x],c1);
update(a[i].x,1,c2);
}
printf("%lld\n",ans);
}
return 0;
}