51nod 1053 最大M子段和 V2 (链表 对经典dp进行优化)

来源:互联网 发布:java专业技能 编辑:程序博客网 时间:2024/05/17 02:55

把所有连续正数或者负数整合起来。比如 1 2 3 -1 -2 6 整合后是6 -3 6.这样用set存储他们的绝对值。每次让绝对值最小的和两边的进行整合。每次整合肯定会少一个正数。比如当前绝对值最小的是负数,把周围两个正数和这个负数进行合并。形成一个正数。把这三个去掉,入队新的这个正数。如果最小的为正数,正好把正数和周围的负数合并。少一个正数。最后剩下m个最大的正数序列就行了。每次少那个用所有正数和减去最小的那个数的绝对值。

#include <iostream>#include <stdio.h>#include <stdlib.h>#include <algorithm>#include <string.h>#include <vector>#include <limits>#include <set>#include <map>using namespace std;int n,m,l[233333],r[233333];long long a[233333];typedef pair<long long,int> pii;set<pii> ps;void del(int a){    int L=l[a],R=r[a];    if(L) r[L]=R;    if(R) l[R]=L;}int main(){    int N;    scanf("%d%d",&N,&m);    long long ans=0,sum=0,ds=0;    for(int i=1;i<=N;i++)    {        int x;        scanf("%d",&x);        if((sum>0&&x<0)||(sum<0&&x>0))        {            a[++n]=sum;            ds+=sum>0;            if(n!=1)ps.insert(pii(abs(sum),n));            sum=0;        }        sum+=x;        if(x>=0) ans+=x;    }    if(n%2==1)    {a[++n]=sum;    ds+=sum>0;    ps.insert(make_pair(abs(sum),n));}    else a[1]+=sum;  //  for(int i=1;i<=n;i++)    //     printf("%d\n",a[i]);    ps.insert(pii(abs(a[1]),1));    for(int i=1;i<=n;i++)l[i]=i-1,r[i]=(i<n)?i+1:1;    l[1]=n;    while(ds>m)    {        int cur=ps.begin()->second;        ps.erase(ps.begin());        if((a[cur]<0&&(!l[cur]||!r[cur]))||!a[cur]) continue;        ps.erase(pii(abs(a[l[cur]]),l[cur]));        ps.erase(pii(abs(a[r[cur]]),r[cur]));        ans-=abs(a[cur]);        a[cur]+=a[l[cur]]+a[r[cur]];        del(l[cur]); del(r[cur]);        ps.insert(pii(abs(a[cur]),cur));        --ds;    }    printf("%lld\n",ans);}