做題的時候湊的規律,其實可以 用式子推一下的。
題意: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一項。那么,為了使答案變優,需要滿足的條件是EjKi≤EiKj。也即Ei/Ki≥Ej/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 }