【背景描述】

一排 N 个数, 第 i 个数是 Ai , 你要找出 K 个不相邻的数, 使得他们的和最大。

请求出这个最大和。

【输入格式】

第一行两个整数 N 和 K。

接下来一行 N 个整数, 第 i 个整数表示 Ai 。

【输出格式】

一行一个整数表示最大和, 请注意答案可能会超过 int 范围

【样例输入】

3 2

4 5 3

【样例输出】

7

【数据范围】

对于 20% 的数据, N, K ≤ 20 。

对于 40% 的数据, N, K ≤ 1000 。

对于 60% 的数据, N, K ≤ 10000 。

对于 100% 的数据, N, K ≤ 100000 , 1 ≤ Ai ≤ 1000000000。

首先把所有元素放入一个set中,每次选权值最大的元素x,然后把x删掉,以及x相邻的元素删掉,在x的位置加入一个新元素,a[x]=a[pre[x]]+a[nex[x]]-a[x]    ,pre[x],nex[x]是用链表维护的x相邻的元素,然后把修改后的x插入set中,

比如


修改a[3]=2,插入set中,把链表的指向改为图中蓝色标记的样子(把不合法的点设为-INF,防止被搜到,a[0]=-INF

#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
#define LL long long
#define maxn 100005
using namespace std;
int n,K,t;
int nex[maxn],pre[maxn];
LL ans=0;
LL a[maxn*2];
struct node
{
    LL first;
    int second;
    friend bool operator <(node a,node b){
       return a.first==b.first? a.second<b.second : a.first>b.first;
    }  
};
set< node > s;
node tmp; 
void hb(int x)
{
     tmp.first=a[x]; tmp.second=x; s.erase(tmp);
     if(nex[x]){ tmp.first=a[nex[x]]; tmp.second=nex[x]; s.erase(tmp);}
     if(pre[x]){ tmp.first=a[pre[x]]; tmp.second=pre[x]; s.erase(tmp);}
     a[x]=a[nex[x]]+a[pre[x]]-a[x];
     tmp.first=a[x]; tmp.second=x; s.insert(tmp);
     int pr=pre[x],to=nex[x];
     nex[x]=nex[to];
     pre[x]=pre[pr];
     if(pre[pr])  nex[pre[pr]]=x;
     if(nex[to])  pre[nex[to]]=x;
}
int main()
{
     //freopen("in.txt","r",stdin);
     //freopen("so7.in","r",stdin);
     //freopen("so.out","w",stdout);
     memset(a,-0xf,sizeof(a));
     scanf("%d%d",&n,&K);
     for(int i=1;i<=n;i++){ 
        scanf("%lld",&a[i]);
        tmp.first=a[i]; tmp.second=i;
        s.insert(tmp);
     }
     for(int i=1;i<=n;i++){
        nex[i]=i+1; pre[i]=i-1;
     }
    nex[n]=0; pre[1]=0;
    set< node > ::iterator it;
    for(int i=1;i<=K;i++){
        it=s.begin();
        ans+=(*it).first;
        t=(*it).second;
        hb(t);
    }
    printf("%lld",ans);
    //while(1);
    return 0;
}




posted @ 2017-08-07 21:16  HunterxHunterl  阅读(212)  评论(0编辑  收藏  举报