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 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM