set+链表 【POJ Challenge】生日礼物

2288: 【POJ Challenge】生日礼物

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 841 Solved: 255
[Submit][Status][Discuss]
Description
ftiasch 18岁生日的时候,lqp18_31给她看了一个神奇的序列 A1, A2, …, AN. 她被允许选择不超过 M 个连续的部分作为自己的生日礼物。
自然地,ftiasch想要知道选择元素之和的最大值。你能帮助她吗?
Input
第1行,两个整数 N (1 ≤ N ≤ 105) 和 M (0 ≤ M ≤ 105), 序列的长度和可以选择的部分。
第2行, N 个整数 A1, A2, …, AN (0 ≤ |Ai| ≤ 104), 序列。
Output
一个整数,最大的和。
Sample Input
5 2
2 -3 2 -1 2
Sample Output
5

可以发现,连续的一段同号整数一定被一起选上.所以把连续的整数合并,去掉0.
先选上所有的正数段,如果段数<=m,直接输出,如果大于,就需要添上一段负数使两个正数段连在一起,或者去掉一段正数。所以把所有数改成正数,用set选最小的。
而且不能选连续的两段,如果左右端点是负数,选他没必要,不能选。
具体怎么搞,见这个题解(思路相同)

#pragma GCC optimize("O3")
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<set>
#include<cmath>
#define N 100005
#define ll long long
using namespace std;
int n,m,num,tot;
int fro[N],nex[N];
struct node
{
    int id;ll h;
    node(){}node(int x,ll y){id=x;h=y;}
    inline friend bool operator <(const node &x,const node &y){return (x.h!=y.h)?x.h<y.h:x.id<y.id;}
};set<node> s;
ll a[N],ans;
int main()
{
    scanf("%d%d",&n,&m);ll x;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&x);if(x==0)continue;
        if(tot==0){a[++tot]=x;continue;}
        if((x>0&&a[tot]>0)||(x<0&&a[tot]<0))a[tot]+=x;
        else a[++tot]=x;
    }
    for(int i=1;i<=tot;i++)if(a[i]>0){num++;ans+=a[i];}
    if(num<=m){cout<<ans;return 0;}
    m=num-m;int p=1;if(a[p]<0)p++;if(a[tot]<0)tot--;
    for(int i=p;i<=tot;i++)
    {
        if(a[i]<0)a[i]=-a[i];
        fro[i]=i-1;nex[i]=i+1;
        s.insert(node(i,a[i]));
    }
    fro[p]=0;nex[0]=p;nex[tot]=0;a[0]=10000000000000ll;
    while(m--)
    {
        int x=s.begin()->id;
        ans-=a[x];
        a[x]=-a[x];
        a[x]+=a[fro[x]];
        a[x]+=a[nex[x]];
        s.erase(s.begin());
        s.erase(node(fro[x],a[fro[x]]));
        s.erase(node(nex[x],a[nex[x]]));
        s.insert(node(x,a[x]));
        if(fro[fro[x]])nex[fro[fro[x]]]=x;
        if(nex[nex[x]])fro[nex[nex[x]]]=x;
        fro[x]=fro[fro[x]];
        nex[x]=nex[nex[x]];
    }
    cout<<ans;
}
原文地址:https://www.cnblogs.com/QTY2001/p/7632667.html