• BZOJ2288:[POJ Challenge]生日礼物


    浅谈堆:https://www.cnblogs.com/AKMer/p/10284629.html

    题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=2288

    首先我们可以把同符号的全部合成一个数,第一个如果是负数就扔了,最后一个也是。

    然后把所有的正数都加起来,记段数为(x),若(x<=m)则这就是正确答案,否则我们需要使用一些手段让(x)降低为(m)。比如扔掉某些权值很小的正整数,或者加上某些绝对值很小的负数,这样都会使(x--)。但是如果我同时扔掉某个权值很小的正整数又加上这个数两边的负数显然是很蠢的,又或者我加上了某个绝对值很小的负数又扔掉这个负数两边的正数,显然也是很蠢的。

    于是,我们往堆里扔所有数的绝对值,做一遍数据备份,不过每次是减去堆顶的值就行了。

    时间复杂度:(O(nlogn))

    空间复杂度:(O(n))

    代码如下:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int maxn=1e5+5;
    
    int a[maxn];
    int n,m,ans,cnt;
    
    int read() {
    	int x=0,f=1;char ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    	return x*f;
    }
    
    struct Linked_List {
        int lst,nxt,val,in_heap;
    
        Linked_List() {}
    
        Linked_List(int _lst,int _nxt,int _val) {
            lst=_lst,nxt=_nxt,val=_val;
        }
    }L[maxn];
    
    struct Heap {
        int tot;
        int tree[maxn];
    
        bool less(int id1,int id2) {return L[id1].val<L[id2].val;}
    
        void up(int pos) {
            while(pos>1) {
                if(less(tree[pos],tree[pos>>1])) {
                    swap(tree[pos],tree[pos>>1]);
                    swap(L[tree[pos]].in_heap,L[tree[pos>>1]].in_heap);
                    pos>>=1;
                }
                else break;
            }
        }
    
        void down(int pos) {
            int son=pos<<1;
            while(son<=tot) {
                if(son<tot&&less(tree[son|1],tree[son]))son|=1;
                if(less(tree[son],tree[pos])) {
                    swap(tree[son],tree[pos]);
                    swap(L[tree[son]].in_heap,L[tree[pos]].in_heap);
                    pos=son,son=pos<<1;
                }
                else break;
            }
        }
    
        void ins(int v) {tree[++tot]=v,L[v].in_heap=tot,up(tot);}
    
        int pop() {
            int res=tree[1];
            tree[1]=tree[tot--];
            L[tree[1]].in_heap=1;
            down(1);return res;
        }
    
        void del(int id) {
            if(id==tot) {tot--;return;}
            tree[id]=tree[tot--];
            L[tree[id]].in_heap=id;
            if(id==1)down(id);
            else if(id==tot)up(id);
            else up(id),down(id);
        }
    }T;
    
    void work() {
    	for(int i=1;i<=n;i+=2)
    		ans+=a[i],m--;
    	for(int i=1;i<=n;i++) {
    		L[i]=Linked_List(i-1,i+1,abs(a[i]));
    		T.ins(i);
        }
        while(m<0) {
            int id=T.pop(),lst=L[id].lst,nxt=L[id].nxt;ans-=L[id].val;
            if(!lst) {
                T.del(L[nxt].in_heap);m++;
                L[L[nxt].nxt].lst=0;continue;
            }
            if(nxt==n+1) {
                T.del(L[lst].in_heap);m++;
                L[L[lst].lst].nxt=n+1;continue;
            }
            T.del(L[lst].in_heap),T.del(L[nxt].in_heap);
            L[lst].val=L[lst].val+L[nxt].val-L[id].val;T.ins(lst);
            L[lst].nxt=L[nxt].nxt,L[L[nxt].nxt].lst=lst;m++;
        }
        printf("%d
    ",ans);
    }
    
    int main() {
    	n=read(),m=read();
    	if(!m) {puts("0");return 0;}
    	for(int i=1;i<=n;i++) {
    		int x=read();
    		if(!x)continue;
    		if(!cnt&&x<0)continue;
    		if(!cnt)a[++cnt]=x;
    		else {
    			if((a[cnt]<0)==(x<0))a[cnt]+=x;
    			else a[++cnt]=x;
    		}
    	}
    	if(a[cnt]<0)cnt--;
    	n=cnt;work();
    }
    
  • 相关阅读:
    jquery获取当前元素的坐标
    JS获取鼠标点击位置坐标
    基于jquery fly插件实现加入购物车抛物线动画效果
    PHP下载远程图片的方法
    IQ测试
    PHP面试题
    Apache服务器错误问题Internal Server Error
    php获取当前浏览器完整地址
    jQuery检测滚动条到达顶部或底部
    scrapy 命令
  • 原文地址:https://www.cnblogs.com/AKMer/p/10295481.html
Copyright © 2020-2023  润新知