POJ 1990 MooFest

题目大意:

        现只有一个测例,共有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, 符合相关要求(条件)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值