1. 程式人生 > >bzoj3709: [PA2014]Bohater 貪心

bzoj3709: [PA2014]Bohater 貪心

分享圖片 a20 onclick stdin struct 技術 隨著 怎麽 因此

~~~題面~~~

題解:

  首先有一個比較明顯的策略,肯定先要把能帶給自己受益的先選完,然後再以最佳狀態去打那些會給自己帶來損失的怪。

  對於前一部分(可以帶來受益的怪),顯然我們需要先從代價小的打起,因為這樣可以把生命值越積越多,打代價大的怪也更容易成功。

  那麽對於後一部分怎麽辦呢?我們需要從受益大的打起,為什麽?

  證明:

    假設一個怪的受益為back,代價為cost,那麽首先假設我們打完所有怪之後剩下have的生命值,那麽have的大小是固定的,不會隨著操作順序而改變,因此我們可以考慮用這個來倒推最優策略。

    那麽就是要使得這個倒推盡可能成功,觀察一下,在倒推的過程中,相當於是不斷的後悔打某個怪,那麽就相當於減去back,加上cost。

    因此這就是一個和上一部分類似的問題,所以在倒推的時候需要按照back從小到大取,那麽從正向來看,就是按照back從大到小取。

技術分享圖片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define R register int
 4 #define AC 250100
 5 #define LL long long
 6  
 7 int n;
 8 LL have;
 9 int q[AC], top;
10 struct node{
11     int cost, back, id;
12 }s[AC]; 13 14 inline int read() 15 { 16 int x = 0;char c = getchar(); 17 while(c > 9 || c < 0) c = getchar(); 18 while(c >= 0 && c <= 9) x = x * 10 + c - 0, c = getchar(); 19 return x; 20 } 21 22 inline bool cmp1(node a, node b){ 23 return
a.cost < b.cost; 24 } 25 26 inline bool cmp2(node a, node b){ 27 return a.back > b.back; 28 } 29 30 void pre() 31 { 32 n = read(), have = read(); 33 for(R i = 1; i <= n; i ++) 34 s[i].cost = read(), s[i].back = read(), s[i].id = i; 35 } 36 37 void work() 38 { 39 sort(s + 1, s + n + 1, cmp1); 40 for(R i = 1; i <= n; i ++) 41 if(s[i].cost <= s[i].back) 42 { 43 if(s[i].cost >= have) {printf("NIE\n"); return ;} 44 have += s[i].back - s[i].cost; 45 q[++top] = s[i].id; 46 } 47 sort(s + 1, s + n + 1, cmp2); 48 for(R i = 1; i <= n; i ++) 49 if(s[i].cost > s[i].back) 50 { 51 if(s[i].cost >= have) {printf("NIE\n"); return ;} 52 have += s[i].back - s[i].cost; 53 q[++top] = s[i].id; 54 } 55 printf("TAK\n"); 56 for(R i = 1; i <= top; i ++) printf("%d ", q[i]); 57 } 58 59 int main() 60 { 61 //freopen("in.in", "r", stdin); 62 pre(); 63 work(); 64 //fclose(stdin); 65 return 0; 66 }
View Code

bzoj3709: [PA2014]Bohater 貪心