• 【BZOJ2288】生日礼物 [贪心]


    生日礼物

    Time Limit: 10 Sec  Memory Limit: 128 MB
    [Submit][Status][Discuss]

    Description

      ftiasch 18岁生日的时候,lqp18_31给她看了一个神奇的序列 A1, A2, ..., AN. 她被允许选择不超过 M 个连续的部分作为自己的生日礼物。

      自然地,ftiasch想要知道选择元素之和的最大值。你能帮助她吗?

    Input

      第1行,两个整数 N  和 M , 序列的长度和可以选择的部分。

      第2行, N 个整数 A1, A2, ..., AN , 序列。

    Output

      一个整数,最大的和。

    Sample Input

      5 2
      2 -3 2 -1 2

    Sample Output

      5

    HINT

      1 ≤ N ≤ 105, 0 ≤ M ≤ 105, 0 ≤ |Ai| ≤ 104

    Solution

      首先,我们可以把权值正负相同的连续的一段合并起来。Ans+=(所有正数),块数++。

      然后把每一段的绝对值加入到小根堆里面。每次贪心取出最小的来,块数减去 1 直到满足题目要求为止。

      为什么这样可以对呢?我们来讨论一下:

        1. 如果删去的段是正数, 那么相当于不取这个

        2. 如果删去的段是负数,那么相当于取了这个段合并它左右的两个段。

      但是!这样会有一个问题!就是无法考虑连续取5个段及以上的情况,并且无法保证:取了一个数不取相连的两个数(会导致块数不减)。

      所以判断一下,每次取段的时候,删去左右两个小段加上一个大段他们三个合并的值)即可。

    Code

      1 #include<iostream>    
      2 #include<string>    
      3 #include<algorithm>    
      4 #include<cstdio>    
      5 #include<cstring>    
      6 #include<cstdlib>
      7 #include<cmath>
      8 #include<queue>
      9 using namespace std;  
     10 typedef long long s64;
     11   
     12 const int ONE = 200005;
     13 const int INF = 1000000007;
     14 
     15 int n, m;
     16 int a[ONE], A[ONE];
     17 int pre[ONE], suc[ONE];
     18 int Ans, block;
     19 
     20 struct power
     21 {
     22         int id, val;
     23         bool operator <(power a) const
     24         {
     25             return a.val < val;
     26         }
     27 };
     28 priority_queue <power> q;
     29 
     30 int get()
     31 {    
     32         int res=1,Q=1;char c;    
     33         while( (c=getchar())<48 || c>57 ) 
     34         if(c=='-')Q=-1; 
     35         res=c-48;     
     36         while( (c=getchar())>=48 && c<=57 )    
     37         res=res*10+c-48;    
     38         return res*Q;
     39 }
     40 
     41 
     42 int main()
     43 {
     44         n = get();    m = get();
     45         for(int i = 1; i <= n; i++) a[i] = get();
     46         int from = 1;    while(a[from] <= 0) from++;
     47         int to = n;        while(a[to] <= 0) to--;
     48         
     49         n = 0;
     50         for(;from <= to;)
     51         {
     52             if( (a[from-1] <= 0 && a[from] <= 0) || (a[from-1] > 0 && a[from] > 0)) 
     53             A[n] += a[from];
     54             else A[++n] = a[from];
     55             from++;
     56         }
     57         
     58         for(int i = 1; i <= n; i++)
     59         {
     60             pre[i] = i - 1;
     61             suc[i] = i + 1;
     62             if(A[i] > 0) Ans += A[i], block++;
     63             A[i] = abs(A[i]);
     64             q.push( (power){i, A[i]} );
     65         }    
     66         
     67         if(block <= m) {printf("%d", Ans); return 0;}
     68         
     69         pre[1] = suc[n] = 0;
     70         
     71         for(;;)
     72         {
     73             for(;;)
     74             {
     75                 power u = q.top();
     76                 if(u.val != A[u.id]) q.pop();
     77                 else break;
     78             }
     79             
     80             power u = q.top();    q.pop();
     81             Ans -= u.val;
     82             
     83             if(pre[u.id] == 0)    A[suc[u.id]] = INF, pre[suc[u.id]] = 0;
     84             else
     85             if(suc[u.id] == 0)    A[pre[u.id]] = INF, suc[pre[u.id]] = 0;
     86             else
     87             {
     88                 A[u.id] = A[pre[u.id]] + A[suc[u.id]] - A[u.id];
     89                 A[pre[u.id]] = A[suc[u.id]] = INF;
     90                 pre[u.id] = pre[pre[u.id]];
     91                 suc[u.id] = suc[suc[u.id]];
     92                 pre[suc[u.id]] = suc[pre[u.id]] = u.id;
     93                 q.push( (power){u.id, A[u.id]} ); 
     94             }
     95             
     96             block--;    if(block <= m) break;
     97         }
     98         
     99         printf("%d", Ans);
    100 }
    View Code

     

  • 相关阅读:
    Linux异常现场--pt_regs浅析
    内核调试--确认结构体的size和结构体成员的偏移
    Linux内核中root_domain的建立与初始化
    solr学习笔记-全量更新与增量更新,去除html标签
    oracle 替换clob里面的某个特定的字符串
    oracle重置序列从1开始
    oracle提取汉字拼音首字母
    layer.open的yes函数中获取弹出层(子集iframe)中的元素或参数
    java.util.Date日期时间工具类
    js操作将数字转换成 , 逗号分割的字符串并追加‘万’字
  • 原文地址:https://www.cnblogs.com/BearChild/p/7251246.html
Copyright © 2020-2023  润新知