hdu 4882 ZCC Loves Codefires (贪心 推导)

题目链接

做题的时候凑的规律,其实可以 用式子推一下的。

题意:n对数,每对数有e,k, 按照题目的要求(可以看下面的Hint就明白了)求最小的值。

分析:假设现在总的是sum, 有两个e1 k1 e2 k2

则先选e1 为 (sum+e1)*k1+(sum+e1+e2)*k2

先e2: (sum+e2)*k2 + (sum+e1+e2)*k1.

比较两个式子发现不同的部分分别是 e1*k2   e2*k1; 比较大小移向 e1/k1  e2/k2, 那个小,就选那个,能达到最小。 

官方题解:

考察序列中相邻的两题i, j(i在前)。交换它们后,解出它们之前的题目所带来的时间对答案的贡献是不变的,它们对

它们后面的题目的贡献也是不变的,其他题目之间对答案的贡献自然也是不变的。唯一的变化就是,原来的EiKj一项变

成了EjKi一项。那么,为了使答案变优,需要满足的条件是EjKiEiKj。也即Ei/KiEj/Kj

那么,最优解序列Ai一定满足,EAi/KAi是递增的。

排序一遍即可。

 1 #include <stdio.h>
 2 #include <iostream>
 3 #include <string.h>
 4 #include <stdlib.h>
 5 #include <algorithm>
 6 using namespace std;
 7 const int maxn = 100000+10;
 8 int n;
 9 struct node
10 {
11     int e, k;
12     double x;
13 }p[maxn];
14 
15 bool cmp(node a, node b)
16 {
17     return a.x < b.x;
18 }
19 int main()
20 {
21     int i;
22     __int64 sum, ans;
23     while(~scanf("%d", &n))
24     {
25         for(i = 0; i < n; i++)
26         {
27             scanf("%d", &p[i].e);
28         }
29         for(i = 0; i < n; i++)
30         {
31             scanf("%d", &p[i].k);
32             p[i].x = (double)(p[i].e*1.0/p[i].k*1.0);
33         }
34         sort(p, p+n, cmp);
35         sum = 0; ans = 0;
36         for(i = 0; i < n; i++)
37         {
38             sum += p[i].e;
39             ans += sum*p[i].k;
40         }
41         cout<<ans<<endl;
42     }
43     return 0;
44 }
原文地址:https://www.cnblogs.com/bfshm/p/3866407.html