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; }
pain and happy in the cruel world.