题目描述
Farmer John went to cut some wood and left N (2 ≤ N ≤ 100,000) cows eating the grass, as usual. When he returned, he found to his horror that the cluster of cows was in his garden eating his beautiful flowers. Wanting to minimize the subsequent damage, FJ decided to take immediate action and transport each cow back to its own barn.
Each cow i is at a location that is Ti minutes (1 ≤ Ti ≤ 2,000,000) away from its own barn. Furthermore, while waiting for transport, she destroys Di (1 ≤ Di ≤ 100) flowers per minute. No matter how hard he tries, FJ can only transport one cow at a time back to her barn. Moving cow i to its barn requires 2 × Ti minutes (Ti to get there and Ti to return). FJ starts at the flower patch, transports the cow to its barn, and then walks back to the flowers, taking no extra time to get to the next cow that needs transport.
Write a program to determine the order in which FJ should pick up the cows so that the total number of flowers destroyed is minimized.
有n头奶牛跑到FJ的花园里去吃花儿了,它们分别在距离牛圈T分钟处吃花儿,每分钟会吃掉D朵卡哇伊的花儿,(此处有点拗口,不要在意细节啊!),FJ现在要将它们给弄回牛圈,但是他每次只能弄一头回去,来回用时总共为2*T分钟,在这段时间内,其它的奶牛会继续吃FJ卡哇伊的花儿,速度保持不变,当然正在被赶回牛圈的奶牛就没口福了!现在要求以一种最棒的方法来尽可能的减少花儿的损失数量,求奶牛吃掉花儿的最少朵数!
输入输出格式
输入格式
Line 1: A single integer N
Lines 2..N+1: Each line contains two space-separated integers, Ti and Di, that describe a single cow's characteristics
输出格式
Line 1: A single integer that is the minimum number of destroyed flowers
样例
INPUT
6
3 1
2 5
2 3
3 2
4 1
1 6
OUTPUT
86
HINT
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.
SOLUTION
排序+贪心
注意:题意有一点没表述清楚,就是当FJ在去赶走奶牛C的路上的话,奶牛C不会吃花,(我也不知道为什么,反正不这么算样例都过不去qwq)
gy说是这题的贪心用数学归纳法可以证明,虽然我并没有把这题的正解按数学归纳法理解(数论渣qwq)。网上的题解大多都没说为什么就直接把两头牛的情况扩展到整体的情况了(所以说是数学归纳法啦)
我觉得也可以这么理解:如果我们钦定两头破坏级最大的牛并把它们放在队首,显然地,捉走它们两个的先后顺序并没有对在它们后面的奶牛的破坏产生影响(因为赶走这两头牛的总时间不变),所以对于这两头牛,我们可以把它们单独拎出来考虑先后顺序。
设一头牛为A,另一头牛为B,若使先赶走A的破坏程度大于B,则有:
\[2*T_A*D_B>2*T_B*D_A\iff \frac {T_A}{D_B}>\frac {T_B}{D_A}\]
\(Update.\)从lyd书上抄的然后我们能够根据冒泡排序的知识,有:任何一个序列都能通过邻项交换的方式变为有序序列。故当逆序对数为0,即按上面规律排序时就是最优策略。
用sort直接排序,再在计算答案时注意我写在开头的话即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
typedef long long LL;
const int N=101000;
int n,sum=0;
LL ans=0;
struct COW{int d,t;double w;}cow[N];
inline int read(){
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9') {x=x*10+ch-48;ch=getchar();}
return x*f;}
bool cmp(COW a,COW b) {return a.w<b.w;}
int main(){
int i,j;
n=read();
for (i=1;i<=n;++i) {cow[i].t=read();cow[i].d=read();
cow[i].w=(double)cow[i].t/cow[i].d;sum+=cow[i].d;}
sort(cow+1,cow+1+n,cmp);
for (i=1;i<=n;++i) {ans+=2*cow[i].t*(sum-cow[i].d);sum-=cow[i].d;}
printf("%lld\n",ans);
return 0;
}