[题解]NKOJ 3102取数(乱搞)

Posted fanyujun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[题解]NKOJ 3102取数(乱搞)相关的知识,希望对你有一定的参考价值。

题目描述

n个整数组成的一个环,现在要从中取出m个数,取走一个数字就不能取跟它相邻的数字(相邻的数不能同时取)。要求取出的数字的总和尽可能大,问这个最大和是多少? 如果无解,请输出“Error!”

输入输出格式

输入格式:

 

第一行包含两个正整数n、m。 第二行为n个整数Ai。

 

输出格式:

 

仅一个整数,表示所求结果。如果无解输出“Error!”,不包含引号。

输入输出样例

输入样例#1: 
7 3 
1 2 3 4 5 6 7
输出样例#1: 
15
输入样例#2: 
7 4 
1 2 3 4 5 6 7
输出样例#2: 
Error!
输入样例#3: 
8 4
8 5 6 2 3 4 8 9
输出样例#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 }

 


















以上是关于[题解]NKOJ 3102取数(乱搞)的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ2716 & NKOJ2739:[Violet 3]天使玩偶——题解

CQOI2015多项式题解 (NKOJ3252)

BZOJ 1045 糖果传递 题解 递推乱搞就对了

luogu P1452 题解

UVALive 7503 Change(乱搞)题解

SPOJ - POLYNOM Polynomial(数论乱搞)题解