bzoj2288: 【POJ Challenge】生日礼物

心态都崩了做了一上午。。。

首先想的就是把连续同正负性的合并起来,那么相邻数的正负性是反的。

然后我想的是建一个链表倒着删除到m

这个时候有一个奇妙的想法,把正的取和,放进链表里面的数都取绝对值,假如删掉正的可以看作少了一段,删掉负的可以看作把两个正的连在一起,按照数据备份那个退流的思想做

尴尬的是我发现我不会判边界,冥冥中记忆是在两边放哨兵节点,没写硬判fail得头皮发麻,结果是%了一发自己。。

 

upd:第二次做的时候就感觉好很多了。首先是先想了想DP,结果发现状态数都要nm没办法再优化了

然后考虑下这种链表类似退流的毒瘤题……

连续的正负显然是分成一组,然后就自然而然的想到和上面一样倒着玩。。。(果然是本人)

正数是收益,负数是代价显然很不资瓷(貌似资瓷这个东西的只有最大权闭合图?),早上做了一道很类似的转换问题的方法,我们希望的是收益最大,那么先正数取sum,然后再减去小的,这样问题就转换成选取代价最小的了,按照数据备份的做法做就可以了~(这次代码写的也好看一些啊)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;

struct node
{
    int c,me,b;
    bool friend operator>(node n1,node n2){return n1.c>n2.c;}
}a[110000];int len,bef[110000],aft[110000];
priority_queue<node,vector<node>,greater<node> >q;
void ins(int ss)
{
    if(len==1&&ss<0)return ;
    len++;
    a[len].c=abs(ss);a[len].me=len;a[len].b=1;
//    printf("%d ",a[len].c);
    q.push(a[len]);
    bef[len]=len-1, aft[len]=len+1;
}

int c[110000];bool v[110000];
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    if(m==0){printf("0\n");return 0;}
    
    int ss=0,sum=0;len=0;
    ins(1<<30);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&c[i]);
        if((ss>=0&&c[i]>=0)||(ss<=0&&c[i]<=0))ss+=c[i];
        else 
        {
            ins(ss);
            if(ss>0)sum+=ss;
            ss=c[i];
        }
    }
    if(ss>0)ins(ss),sum+=ss;
    ins(1<<30);
    bef[1]=-1;aft[len]=-1;

    if((len+1)/2<=m){printf("%d\n",sum);return 0;}
    int mmax=0;node t;bool zz1=false,zz2=false;
    memset(v,true,sizeof(v));
    for(int i=len/2-1;i>=1;i--)
    {
        t=q.top();q.pop();
        while(v[t.me]==false)t=q.top(),q.pop();
        sum-=t.c;
        if(i<=m)mmax=max(mmax,sum);
        
        t.c=-t.c;
        if(bef[t.me]!=-1) v[bef[t.me]]=false, t.c+=a[bef[t.me]].c, bef[t.me]=bef[bef[t.me]];
        if(aft[t.me]!=-1) v[aft[t.me]]=false, t.c+=a[aft[t.me]].c, aft[t.me]=aft[aft[t.me]];
        if(bef[t.me]!=-1) aft[bef[t.me]]=t.me;
        if(aft[t.me]!=-1) bef[aft[t.me]]=t.me;
        a[t.me].c=t.c;
        
        q.push(t);
        if(q.top().c>0&&i<=m)break; 
    }
    printf("%d\n",mmax);
    return 0;
}

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;

int n,m,a[110000];
int len,c[110000],bef[110000],aft[110000];
struct node
{
    int d,id;
    node(){}
    node(int D,int ID){d=D,id=ID;}
    friend bool operator >(node n1,node n2){return n1.d>n2.d;}
    friend bool operator <(node n1,node n2){return n1.d<n2.d;}
};priority_queue<node,vector<node>,greater<node> >q;
bool inq[110000];
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int ans=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        if(a[i]==0)i--,n--;
        else if(a[i]>0)ans+=a[i];
    }
    
    int sum=0,op=0,cnt=0; len=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]>0)
        {
            if(op==1)
            {
                if(len!=0)c[++len]=sum;
                sum=0, op=0;
            }
            sum+=a[i];
            
        }
        else 
        {
            if(op==0)
            {
                if(sum!=0)c[++len]=sum,cnt++;
                sum=0, op=1;
            }
            sum+=-a[i];
        }    
    }
    if(op==0)c[++len]=sum,cnt++;
    
    c[0]=c[len+1]=(1<<30);
    for(int i=1;i<=len;i++)
    {
        bef[i]=i-1,aft[i]=i+1;
        q.push(node(c[i],i));inq[i]=true;
    }
    
    for(int i=1;i<=cnt-m;i++)
    {
        while(inq[q.top().id]==false)q.pop();
        int k=q.top().id;q.pop();
        int lc=bef[k],rc=aft[k];
        
        ans-=c[k];
        c[k]=c[lc]+c[rc]-c[k];
        bef[k]=bef[lc],aft[k]=aft[rc];
        aft[bef[k]]=k, bef[aft[k]]=k;
        inq[lc]=inq[rc]=false;
        q.push(node(c[k],k));
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-07-04 11:01  AKCqhzdy  阅读(169)  评论(0编辑  收藏  举报