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