描述 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;
}