题目大意:
现只有一个测例,共有N头牛(1 ≤ N ≤ 20,000)站在x轴上的各不相同的坐标上(坐标范围为[1, 20000]),每头牛都有一个听觉门限vi,只有声音大于等于该听觉门限这头牛才能听见,现定义音量为听觉值乘以距离,则两头牛i, j相互交流需要的最小音量为dist[i][j]×max(vi, vj),输入会给出每头牛的坐标和听觉门限(门限范围为[1, 20000]),现要求你输出所有牛两两之间交流所需的最小总音量大小。
注释代码:
/*
* Problem ID : POJ 1990 MooFest
* Author : Lirx.t.Una
* Language : C
* Run Time : 47 ms
* Run Memory : 760 KB
*/
#include <algorithm>
#include <iostream>
#include <cstdio>
//牛的最大数量
#define MAXN 20000
//最大坐标
#define MAXX 20000
using namespace std;
typedef __int64 llg;
//思路:
//对点按照门限值从小到大排序
//则后面的和前面的交流使用的听力值必定为后面那头牛的听力值
//对于当前的牛,前面的牛可以分成两类,一类是坐标小于它的,一类是坐标大于他的
//如果能计算出坐标小于它和大于它的牛的个数和坐标之和则问题就能迎刃而解了
//因此维护两个树状数组,一个记录坐标上牛的个数另一个记录牛的坐标和
struct Point {//一头牛代表一个点
int x;//坐标
int v;//门限
bool//按照门小从小到大排序
operator<(const Point &oth)
const {
return v < oth.v;
}
};
Point p[MAXN];
int loc[MAXN];//记录所有的坐标,以便离散化
int mp[MAXX + 1];//离散化映射,将打坐标映射到小坐标,这样可以减小树状数组的规模
//两个树状数组
int num[MAXX + 1];//记录一定范围内点的数量
//可能超出int范围
llg len[MAXX + 1];//记录一定范围内所有点到坐标0的距离的总和
int lowbit[MAXX + 1];
int n;//奶牛数量
void
num_update(int x) {
while ( x <= n ) {
num[x]++;
x += lowbit[x];
}
}
int
num_query(int x) {
int sum;
sum = 0;
while ( x > 0 ) {
sum += num[x];
x -= lowbit[x];
}
return sum;
}
void
len_update( int x, int d ) {
while ( x <= n ) {
len[x] += d;
x += lowbit[x];
}
}
llg
len_query(int x) {
llg sum;
sum = 0;
while ( x > 0 ) {
sum += len[x];
x -= lowbit[x];
}
return sum;
}
int
main() {
int i;//计数变量
int x;//存储临时坐标值
int nlft, nrht;//当前点左侧和右侧的点数
llg dlft, drht;//当前点左侧点和右侧点的距离和
llg ans;
for ( i = 1; i <= MAXX; i++ ) lowbit[i] = i & -i;
scanf("%d", &n);
for ( i = 0; i < n; i++ ) {
scanf("%d%d", &p[i].v, &p[i].x);
loc[i] = p[i].x;
}
sort(p, p + n);
sort(loc, loc + n);//离散化,由于输入保证各坐标不相同,因此不需要使用unique
for ( i = 0; i < n; i++ ) mp[ loc[i] ] = i + 1;
ans = 0;
for ( i = 0; i < n; i++ ) {
x = p[i].x;
nlft = num_query( mp[x] );
nrht = i - nlft;
dlft = len_query( mp[x] );
drht = len_query(n) - dlft;
//总距离为(nlft*x - dlft)+(drht - nrht*x),化简后得下式
ans += p[i].v * ( drht - dlft + ( nlft - nrht ) * (llg)x );
num_update( mp[x] );
len_update( mp[x], x );
}
printf("%I64d\n", ans);
return 0;
}
无注释代码:
#include <algorithm>
#include <iostream>
#include <cstdio>
#define MAXN 20000
#define MAXX 20000
using namespace std;
typedef __int64 llg;
struct Point {
int x;
int v;
bool
operator<(const Point &oth)
const {
return v < oth.v;
}
};
Point p[MAXN];
int loc[MAXN];
int mp[MAXX + 1];
int num[MAXX + 1];
llg len[MAXX + 1];
int lowbit[MAXX + 1];
int n;
void
num_update(int x) {
while ( x <= n ) {
num[x]++;
x += lowbit[x];
}
}
int
num_query(int x) {
int sum;
sum = 0;
while ( x > 0 ) {
sum += num[x];
x -= lowbit[x];
}
return sum;
}
void
len_update( int x, int d ) {
while ( x <= n ) {
len[x] += d;
x += lowbit[x];
}
}
llg
len_query(int x) {
llg sum;
sum = 0;
while ( x > 0 ) {
sum += len[x];
x -= lowbit[x];
}
return sum;
}
int
main() {
int i;
int x;
int nlft, nrht;
llg dlft, drht;
llg ans;
for ( i = 1; i <= MAXX; i++ ) lowbit[i] = i & -i;
scanf("%d", &n);
for ( i = 0; i < n; i++ ) {
scanf("%d%d", &p[i].v, &p[i].x);
loc[i] = p[i].x;
}
sort(p, p + n);
sort(loc, loc + n);
for ( i = 0; i < n; i++ ) mp[ loc[i] ] = i + 1;
ans = 0;
for ( i = 0; i < n; i++ ) {
x = p[i].x;
nlft = num_query( mp[x] );
nrht = i - nlft;
dlft = len_query( mp[x] );
drht = len_query(n) - dlft;
ans += p[i].v * ( drht - dlft + ( nlft - nrht ) * (llg)x );
num_update( mp[x] );
len_update( mp[x], x );
}
printf("%I64d\n", ans);
return 0;
}
单词解释:
converse:vi, 交谈,谈话
time:vt, 乘以
threshold:n, 阈值,临界值,门限值
hearing:n, 听力,听觉
deafening:adj, 整耳欲聋的
roar:n. 咆哮; vt, 咆哮,嚎叫
hay bale:n, 干草捆
fest:n, 集会,节日
moo:vi, 哞哞叫; n, 牛叫声
ridge:n, 山脊,山脉
clover:n, 三叶草
modulo:prep, 以...为模
meet the property:vi, 符合相关要求(条件)