set so 就

   

问题 B: 就

时间限制: 1 Sec  内存限制: 512 MB

题目描述

就so.in/.out

【背景描述】

一排 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。

   考试时大部分人应该都自豪的写出了n*n的DP,能A60分,结果正解是贪心。对,就是贪心,最先选择最大的一个点,明显这不一定是最优解,而且他周围的两个点都没办法选了,而他的值加进了ans无法再踢除。。

   这些问题用一个set+链表就解决了。选了一个点,就把他周围两个点用链表缩成一个,权值赋成左边点权值+右边点权值-自己权值。这个就是用来反悔的。如果选了新的点,相当于向ans里加了A+C-B,而原来ans里加了B,B抵消了,

    就相当于没加。

   

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<set>
#define ll long long
#define N 100005
#define inf 1000000000
using namespace std;
ll read()
{
	ll sum=0,f=1;char x=getchar();
	while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();}
	while(x>='0'&&x<='9'){sum=sum*10+x-'0';x=getchar();}
	return sum*f;
}
struct hh
{
	int id;
	ll h;
	hh(){}
	hh(int a,ll b)
	{
		h=b;
		id=a;
	}
    friend bool operator <(const hh &a,const hh &b)
    {
    	return (a.h!=b.h) ? (a.h>b.h):(a.id<b.id);
	}
};
set<hh> st;
int nex[N],fro[N],n,k;
ll ans=0,a[N];  
int main()
{
	freopen("so.in","r",stdin);
	freopen("so.out","w",stdout);
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
	{
	   scanf("%lld",&a[i]);
	   nex[i]=i+1;
	   fro[i]=i-1;	
	   st.insert(hh(i,a[i]));
	}a[0]=-1e15;
	nex[n]=0;
    while(k--)
	{
		int x=st.begin()->id;
		ans+=a[x];
		a[x]=-a[x];
		a[x]+=a[fro[x]];
		a[x]+=a[nex[x]];
		st.erase(st.begin());
		st.erase(hh(nex[x],a[nex[x]]));
		st.erase(hh(fro[x],a[fro[x]]));
		st.insert(hh(x,a[x]));
		if(fro[fro[x]])nex[fro[fro[x]]]=x;
		if(nex[nex[x]])fro[nex[nex[x]]]=x;
		nex[x]=nex[nex[x]];
		fro[x]=fro[fro[x]];
	} 
	cout<<ans;
}

posted @ 2017-10-06 20:19  Hzoi_QTY  阅读(171)  评论(0编辑  收藏  举报