[题解]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!\n");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\n",ans);
56     return 0;
57 }

原文地址:https://www.cnblogs.com/fanyujun/p/9415166.html

时间: 2024-10-08 16:42:40

[题解]NKOJ 3102取数(乱搞)的相关文章

[题解]luogu_P1627_中位数(排列乱搞

首先我们只关注大小数量关系,所以把小于b的设为-1,大于b的设为1,只要区间包含b且和为0即为合法 统计时用桶记录左和右边sum出现的次数,把左+右==0的乘起来记到答案里 都是比较套路的吧 #include<bits/stdc++.h> using namespace std; const int maxn=200009; int n,b,a[maxn],p,ans; int sum[maxn],lc[maxn],rc[maxn]; int main(){ scanf("%d%d&

洛谷 P1005 矩阵取数游戏 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1005 题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元

Noip2007矩阵取数游戏题解

题目描述 Description [问题描述] 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n?m的矩阵,矩阵中的每个元素ai,j均 为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 每次取走的各个元素只能是该元素所在行的行首或行尾: 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分=被取走的元素值?2i, 其中i表示第i 次取数(从1 开始编号): 游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出

【题解】CH Round #61 取数游戏

取数游戏 CH Round #61 - 「Adera 10」冬令营热身赛 描述 SJY和CYF在玩一个取数游戏.他们将1~n分别写在n张纸上,随机排成一排,约定SJY先取,只能取走最边上的两张纸之一,然后CYF取:以此循环下去,取到1的人获胜.假设SJY和CYF足够聪明,求SJY获胜的概率. 输入 一个整数n 输出 SJY获胜的概率,保留最简分数形式(若为1,则输出1/1:若为0,则输出0/1). 样例 样例输入1 2 样例输出1 1/1 样例输入2 3 样例输出2 2/3 数据范围与约定 40

【日常学习】【区间DP+高精】codevs1166 矩阵取数游戏题解

题目来自NOIP2007TG3 如果在考场上我现在已经歇菜了吧 今天一整天的时间全部投在这道题上,收获不小. 先上题目 题目描述 Description [问题描述] 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m 的矩阵,矩阵中的每个元素aij均 为非负整数.游戏规则如下: 1. 每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. 每次取走的各个元素只能是该元素所在行的行首或行尾: 3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分= 被取走的元素

【bzoj5108】[CodePlus2017]可做题 拆位+乱搞

题目描述 给出一个长度为 $m$ 的序列 $a$ ,编号为 $a_1\sim a_m$,其中 $n$ 个位置的数已经确定,剩下的位置的数可以任意指定.现在令 $b$ 表示 $a$ 的前缀异或和,求 $\sum\limits_{i=1}^mb_i$ 的最小值. 输入 输入第一行两个非负整数n,m,分别表示原始序列a的长度及剩余元素的个数. 之后m行,每行2个数i,ai,表示一个剩余元素的位置和数值. 1<=N<=10^9,0<=M<=Min(n,10^5),0<=ai<=

bzoj1992鬼谷子的钱袋(二分乱搞)

1192: [HNOI2006]鬼谷子的钱袋 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3223  Solved: 2333 Descriptio 鬼谷子非常聪明,正因为这样,他非常繁忙,经常有各诸侯车的特派员前来向他咨询时政.有一天,他在咸阳游历的时候,朋友告诉他在咸阳最大的拍卖行(聚宝商行)将要举行一场拍卖会,其中有一件宝物引起了他极大的兴趣,那就是无字天书.但是,他的行程安排得很满,他他已经买好了去邯郸的长途马车标,不巧的是出发时间是在

Codeforces Amr and Chemistry(数学+乱搞)

题意:给n个数,每个数每次可以乘二或除以二(向下取整相当于左移或右移),问最少经过多少次操作可以使这n个数变相等. 思路:首先考虑每个数的可能取值,将一个数表示成s*2^k的形式,s是奇数. 那么这个数的所有可能取值为s'*2^x,(s'=s/2,(s/2)/2,.....)且s'*2^x<=100000 因为这题数据范围不大,而且每个值可能的取值不多最多几百个,所以记录1到100000每个值可能被取到的次数以及总操作数,最后从1遍历到100000取最小的ans即可 ps:个人赛这道题做了一下午

学渣乱搞系列之字符串滚动哈希

学渣乱搞系列之字符串滚动哈希 by 狂徒归来 我们假定字符串S = S1S2S3S4S5S6S7S8S9. 我们定义哈希函数为 H(S) = (S1bm-1+S2bm-2+S3bm-3+...+Smb0)mod h.其中b是基数,相当于把字符串看成b进制数. b与h为合适的互素的常数. 如何求取字符串内长度为m的一段的字符子串的哈希值? 假定m = 3. 先求取H([S1...S3]) =  S1b2+S2b1+S3b0. 求取H([S2...S4]) = H([S1...S3])*b + S4