【背景描述】
一排 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;
}