【BZOJ 2288】 生日礼物

【题目链接】

              https://www.lydsy.com/JudgeOnline/problem.php?id=2288

【算法】

            先将这个序列的正负数合并起来,变成一个正负交替的序列

            如果新序列的正数个数小于等于M,那么直接输出正数的和即可

            否则,我们可以将某些正数和负数合并起来,或者不要某些正数

            将所有数按绝对值排序,放入堆中,问题就转化为了 : 在这些数中选出(Cnt - M)个数(其中Cnt为正数的个数),

            选了一个数后相邻的两个数就不能选,使得最后的和尽可能小 

            这个问题可以用CTSC2007数据备份的方法来解决,详见 : https://www.cnblogs.com/evenbao/p/9252503.html

【代码】

           

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
const int INF = 2e9;

struct info
{
        int d,pos;
};

int i,n,m,l,r,cnt,ans,len;
int a[MAXN],b[MAXN],val[MAXN],pre[MAXN],nxt[MAXN];
bool visited[MAXN];
info tmp;

class Heap
{
        private :
                int tot;
                info hp[MAXN];
        public :
                inline bool cmp(info a,info b)
                {
                        return a.d < b.d;        
                }                
                inline void Up(int x)
                {
                        if (x == 1) return;
                        int fa = x >> 1;
                        if (cmp(hp[x],hp[fa])) 
                        {
                                swap(hp[x],hp[fa]);
                                Up(fa);
                        }
                }
                inline void Down(int x)
                {
                        int son = x << 1;
                        if (son > tot) return;
                        if ((son + 1 <= tot) && cmp(hp[son+1],hp[son])) son++;
                        if (cmp(hp[son],hp[x]))
                        {
                                swap(hp[son],hp[x]);
                                Down(son);
                        }
                }
                inline void insert(info x)
                {
                        tot++;
                        hp[tot] = x;
                        Up(tot);
                }
                inline void del()
                {
                        swap(hp[1],hp[tot]);
                        tot--;
                        Down(1);
                }
                inline info get()
                {
                        return hp[1];
                }
} H;

int main() 
{
        
        scanf("%d%d",&n,&m);
        for (i = 1; i <= n; i++) scanf("%d",&a[i]);
        while (n && a[n] <= 0) n--;
        i = 1;
        while (i <= n && a[i] <= 0) i++;
        if (i > n)
        {
                printf("%d\n",0);
                return 0;
        }
        for (; i <= n; i++)
        {
                if ((a[i] > 0 && a[i-1] > 0) || (a[i] <= 0 && a[i-1] <= 0)) b[len] += a[i];
                else b[++len] = a[i];        
        }
        for (i = 1; i <= len; i++)
        {
                if (b[i] > 0)    
                {
                        ans += b[i];
                        cnt++;
                } else b[i] = -b[i];
        }
        if (cnt <= m) 
        {
                printf("%d\n",ans);
                return 0;
        }
        for (i = 1; i <= len; i++)
        {
                pre[i] = i - 1;
                nxt[i] = i + 1;
                H.insert((info){b[i],i});
        }
        b[0] = b[len+1] = INF;
        for (i = m; i < cnt; i++)
        {
                tmp = H.get();
                while (visited[tmp.pos]) 
                {
                        H.del();    
                        tmp = H.get();
                }
                ans -= tmp.d;
                H.del();
                visited[pre[tmp.pos]] = true;
                visited[nxt[tmp.pos]] = true;
                b[tmp.pos] = b[pre[tmp.pos]] + b[nxt[tmp.pos]] - tmp.d;
                nxt[pre[pre[tmp.pos]]] = tmp.pos;
                pre[tmp.pos] = pre[pre[tmp.pos]];
                pre[nxt[nxt[tmp.pos]]] = tmp.pos;
                nxt[tmp.pos] = nxt[nxt[tmp.pos]];
                H.insert((info){b[tmp.pos],tmp.pos});
        }    
        printf("%d\n",ans);
        
        return 0;
    
}

 

posted @ 2018-07-03 08:43  evenbao  阅读(116)  评论(0编辑  收藏  举报