赶吃花的牛 USACO

描述 Description

宁智贤出去砍伐,让N头牛在草地上吃草。当他回来时吃惊的看到这些牛全部都跑到花园里在吃他的美丽花朵。他立即去把每头牛赶回它的牛栏(宁智贤的初始位置是牛栏),每次他只能赶一头牛。
i号牛每分钟要吃掉D_i朵花,距离自己的栏地要T_i分钟路程。不幸的是宁智贤每次只能赶一头牛回栏,再回到花园。请问这些牛最少要吃掉多少朵花?
我们认为,一旦宁智贤在牛栏处定位到要赶的某头牛后,首先会大喊一声,然后这头牛就失去了吃花的能力,乖乖的等待宁智贤来将自己赶回牛栏。

数据范围

2 <= N <= 100,000
1 <= T_i <= 2,000,000
1 <= D_i <= 100

输入格式

第一行一个数N。
下面N行,每行两个数T_i D_i,表示第i头牛的数据。

输出格式

一个整数,最少吃掉的花朵数。

样例输入

6
3 1
2 5
2 3
3 2
4 1
1 6

样例输出

86

时间限制

1s

注释 Hint

说明:最好方案赶回牛的次序为 6,2,3,4,1,5

FJ returns the cows in the following order: 6, 2, 3, 4, 1, 5. While
he is transporting cow 6 to the barn, the others destroy 24 flowers;
next he will take cow 2, losing 28 more of his beautiful flora. For
the cows 3, 4, 1 he loses 16, 12, and 6 flowers respectively. When
he picks cow 5 there are no more cows damaging the flowers, so the
loss for that cow is zero. The total flowers lost this way is 24 +
28 + 16 + 12 + 6 = 86.

来源 Source

usaco 月赛 flowerb 宁智贤原名农夫John。。。

跟着注释找可以很显然的得到一个假贪心,即直接将 D i D_i Di排序,然后每次牵回最大的并计算答案输出。
然鹅70分的事实证明这是错的。
于是我们就想到了一个东西叫排序不等式(上午上数学课没听课偷偷学的)我觉得能挺好解释这个贪心的不知道有没有什么更好的证明方法
a 1 < a 2 , b 1 < b 2 a_1 < a_2 , b_1<b2 a1<a2,b1<b2则有 a 2 b 2 > a 1 b 1 a_2b_2 > a_1b_1 a2b2>a1b1
听着很废话,不过排序不等式不止这些,感兴趣的可以查一下,
不过这样就很显然了,大乘大最大,小乘小最小,那么大乘小就在中间,那么对于每两个我们比较的时候将他们交叉乘起来,看谁的影响大,因为计算代价的时候是要乘对方时间的,这样我们就先尽量消除大乘大的,然后再消次打,依次往后。
感觉解释的不是很清楚,感性理解一下,真不懂可以再问我。
记得开long long 本着试一试的态度我没有开long long 就教了,结果让心急的我错教好几次,成功拉低了通过率TT
C o d e Code Code

#include<bits/stdc++.h>

#define N 101
#define gtc() getchar()
#define INF 0x3f3f3f3f
#define rg register
#define MAXN 1000010
#define ll long long

using namespace std;

template <class T>
inline void read(T &s){
	T w = 1, ch = gtc(); s = 0;
	while(!isdigit(ch)){if(ch == '-') w = -1; ch = gtc();}
	while(isdigit(ch)){s = s * 10 + ch - '0'; ch = gtc();}
	s = s * w;
}

ll n;
struct node{
	ll x, y; 
}a[MAXN];

bool cmp(node a, node b){
	return a.y*2*b.x > b.y*2*a.x;
}
ll sum[MAXN];

int main()
{
//	freopen("a.in", "r", stdin);
//	freopen("")
	read(n);
	for(int i = 1;  i <= n; ++i)	
		read(a[i].x), read(a[i].y);
	sort(a+1, a+n+1, cmp);
//	for(int i = 1; i <= n; ++i) printf("%d\n", a[i].y);
	sum[0] = 0;
	for(int i = 1; i <= n; ++i)	 sum[i] = sum[i-1] + a[i].y;
	sum[n+1] = sum[n];
	ll ans = 0;
	for(int i = 1; i <= n; ++i){
//		printf("%d\n", sum[i+1] - sum[i]);
		ans += (a[i].x * 2 * (sum[n] - sum[i]));
	}
	printf("%lld\n", ans);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BIGBIGPPT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值