题目描述
n个整数组成的一个环,现在要从中取出m个数,取走一个数字就不能取跟它相邻的数字(相邻的数不能同时取)。要求取出的数字的总和尽可能大,问这个最大和是多少? 如果无解,请输出“Error!”
输入输出格式
输入格式:
第一行包含两个正整数n、m。 第二行为n个整数Ai。
输出格式:
仅一个整数,表示所求结果。如果无解输出“Error!”,不包含引号。
输入输出样例
输出样例#3:
25
数据范围 对于全部数据:m<=n;-1000<=Ai<=1000 数据编号 N的大小 数据编号 N的大小
1 40 11 2013 2 45 12 5000 3 50 13 10000 4 55 14 49999 5 200 15 111111
6 200 16 148888 7 1000 17 188888 8 2010 18 199999 9 2011 19 199999 10
2012 20 200000
思路:这道题第一眼有点像区间dp,但是n最大可达200000,所以肯定不行,我又想过nlogn的倍增+区间dp,但是好想不可做,
后来翻别人题解发现是优先队列,可以反悔的贪心;优先队列里面存两个值,编号和权值,我们先贪心的选数,但是这样可能是
错的,所以可以设置一个反悔操作,设l[x]为编号x左边元素的编号,r[x]同理,我们贪心选了x后,更优的方案就只可能不选x
而选l[x]+r[x],所以把l[x]的值+r[x]的值,再放回去,选一共m次,就是最终的答案.
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 using namespace std; 6 const int maxn=(200000<<1)+10; 7 int n,m,l[maxn],r[maxn],ans,a[maxn],tot; 8 bool mark[maxn]; 9 struct node{ 10 int id,v; 11 bool operator < (const node &a) const 12 { 13 return v<a.v; 14 } 15 }; 16 priority_queue<node>q; 17 inline int read() 18 { 19 int x=0,f=1;char c=getchar(); 20 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 21 while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();} 22 return x*f; 23 } 24 int main() 25 { 26 freopen("choose.in","r",stdin); 27 freopen("choose.out","w",stdout); 28 n=read();m=read(); 29 if(m>(n>>1)){printf("Error! ");return 0;} 30 for(int i=1;i<=n;++i)a[i]=read(); 31 for(int i=2;i<n;++i) 32 { 33 l[i]=i-1;r[i]=i+1; 34 node tmp; 35 tmp.id=i;tmp.v=a[i]; 36 q.push(tmp); 37 } 38 node tmp; 39 tmp.id=1;l[1]=n;r[1]=2;tmp.v=a[1];q.push(tmp); 40 tmp.id=n;l[n]=n-1;r[n]=1;tmp.v=a[n];q.push(tmp); 41 tot=n; 42 for(int i=1;i<=m;++i) 43 { 44 tmp=q.top();q.pop(); 45 if(mark[tmp.id]){i--;continue;} 46 ans+=tmp.v; 47 node t; 48 a[++tot]=a[l[tmp.id]]+a[r[tmp.id]]-a[tmp.id]; 49 t.id=tot;t.v=a[tot]; 50 l[tot]=l[l[tmp.id]];r[l[l[tmp.id]]]=tot; 51 r[tot]=r[r[tmp.id]];l[r[r[tmp.id]]]=tot; 52 mark[tmp.id]=mark[l[tmp.id]]=mark[r[tmp.id]]=1; 53 q.push(t); 54 } 55 printf("%d ",ans); 56 return 0; 57 }