2151: 种树 - BZOJ

Description

A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n。并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度。但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i号位置和i+1号位置叫相邻位置。值得注意的是1号和n号也算相邻位置!)。最终市政府给园林部门提供了m棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大。如果无法将m棵树苗全部种上,给出无解信息。
Input

输入的第一行包含两个正整数n、m。第二行n个整数Ai。
Output

输出一个整数,表示最佳植树方案可以得到的美观度。如果无解输出“Error!”,不包含引号。
Sample
Input
【样例输入1】
7 3
1 2 3 4 5 6 7
【样例输入2】
7 4
1 2 3 4 5 6
7

Sample
Output
【样例输出1】
15

【样例输出2】
Error!
【数据规模】
对于全部数据:m<=n;
-1000<=Ai<=1000
N的大小对于不同数据有所不同:
数据编号
N的大小 数据编号 N的大小
1 30 11 200
2 35 12 2007
3 40 13 2008
4 45 14
2009
5 50 15 2010
6 55 16 2011
7 60 17 2012
8 65 18 199999
9 200
19 199999
10 200 20 200000

看wikioi的题解完全没有看懂

于是问了群里的人,结果告诉我是费用流优化

搞了半天总算懂了

首先我们把它拆成链,因为这样我们就好做了,我们只要算两遍就行了,一个是[1,n-1](表示n不取)一个是[2,n](表示1不取)

然后构费用流的图(有点奇葩......)

然后跑费用流就行了

但是显然不能跑费用流,承受不了

所以我们模拟费用流

假设我们选了点2(因为费用最大),然后增广后,残留网络是这样的

第1,2,3条路都没了

但是我们可以走从1到2到3,即多了一条路,费用为a[1]+a[3]-a[2]

我们也可以分析出只多出了这条路,其他的路都是没有用的

因为a[2]>=a[1],所以我们不可能从1走到2再走到S,所以没有别的路了

所以对于这种情况我们就用a[pre[i]]+a[next[i]]-a[i]代替a[i],然后删除pre[i]和next[i]

还有一种情况就是i是两端

这种情况想一想就知道了,端点是最大的那么就选端点,然后删掉在端点的那两个值就行了

所以我们用堆维护最大值,做m次就行了

  1 const
2 maxn=200010;
3 var
4 q,h,a,b,pre,next:array[0..maxn]of longint;
5 n,m,tot:longint;
6
7 function max(x,y:longint):longint;
8 begin
9 if x>y then exit(x);
10 exit(y);
11 end;
12
13 procedure swap(var x,y:longint);
14 var
15 t:longint;
16 begin
17 t:=x;x:=y;y:=t;
18 end;
19
20 procedure up(x:longint);
21 var
22 i:longint;
23 begin
24 while x>1 do
25 begin
26 i:=x>>1;
27 if b[q[x]]>b[q[i]] then
28 begin
29 swap(q[x],q[i]);
30 h[q[x]]:=x;
31 h[q[i]]:=i;
32 x:=i;
33 end
34 else break;
35 end;
36 end;
37
38 procedure down(x:longint);
39 var
40 i:longint;
41 begin
42 i:=x<<1;
43 while i<=tot do
44 begin
45 if (i<tot) and (b[q[i+1]]>b[q[i]]) then inc(i);
46 if b[q[i]]>b[q[x]] then
47 begin
48 swap(q[x],q[i]);
49 h[q[x]]:=x;
50 h[q[i]]:=i;
51 x:=i;
52 i:=x<<1;
53 end
54 else break;
55 end;
56 end;
57
58 procedure insert(x:longint);
59 begin
60 inc(tot);
61 h[x]:=tot;
62 q[tot]:=x;
63 up(tot);
64 end;
65
66 procedure delete(x:longint);
67 begin
68 if x=0 then exit;
69 b[q[x]]:=maxlongint;
70 up(x);
71 swap(q[1],q[tot]);
72 h[q[1]]:=1;
73 h[q[tot]]:=tot;
74 dec(tot);
75 down(1);
76 end;
77
78 function f(l,r:longint):longint;
79 var
80 i,u,v,t:longint;
81 begin
82 f:=0;
83 tot:=0;
84 for i:=l to r do
85 begin
86 b[i]:=a[i];
87 insert(i);
88 pre[i]:=i-1;
89 next[i]:=i+1;
90 end;
91 pre[l]:=0;
92 next[r]:=0;
93 for i:=1 to m do
94 begin
95 t:=q[1];
96 inc(f,b[t]);
97 u:=pre[t];
98 v:=next[t];
99 if (u<>0) and (v<>0) then
100 begin
101 b[t]:=b[u]+b[v]-b[t];
102 pre[t]:=pre[u];
103 next[t]:=next[v];
104 next[pre[t]]:=t;
105 pre[next[t]]:=t;
106 down(h[t]);
107 end
108 else
109 begin
110 if u<>0 then next[pre[u]]:=0;
111 if v<>0 then pre[next[v]]:=0;
112 delete(h[t]);
113 end;
114 delete(h[u]);
115 delete(h[v]);
116 end;
117 end;
118
119 procedure main;
120 var
121 i:longint;
122 begin
123 read(n,m);
124 if m*2>n then
125 begin
126 writeln(‘Error!‘);
127 exit;
128 end;
129 for i:=1 to n do
130 read(a[i]);
131 writeln(max(f(1,n-1),f(2,n)));
132 end;
133
134 begin
135 main;
136 end.

时间: 2024-10-19 16:54:02

2151: 种树 - BZOJ的相关文章

【BZOJ 2151】 2151: 种树 (贪心+堆)

2151: 种树 Description A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树.园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n.并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度.但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i号位置和i+1号位置叫相邻位置.值得注意的是1号和n号也算相邻位置!).最终市政府给园林部门提供了m棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大.如果无法将m棵树苗

BZOJ 2151 种树

贪心+priority_queue. #include<iostream> #include<cstdio> #include<cstring> #include<queue> #define maxn 200050 using namespace std; long long n,val[maxn],ans=0,m; bool vis[maxn]; struct node { long long w,pos; friend bool operator &l

BZOJ 2151 种树 贪心+优先队列+HASH

题意:链接 方法:贪心+优先队列 解析: 首先裸上贪最大的肯定不对. DP可行么?可行,两个数组一个记录选一个记录不选好像差不多n^2? 不过还是想想贪心. 贪最大的为什么不对? 因为有可能它旁边的两个加起来比它更优越? 所以能否找到一点关系呢? 既然话都说到这了,两个加起来可能更优越. 所以我们在选了最大的之后是否应该回推一个值呢?代表选旁边俩. 我们发现选旁边俩是两个单位,选一个是一个单位,如果我们推回去某个值后这个值相当于对应删去一个单位选两个单位,即增加一个单位,这显然不会影响最终我们选

bzoj 2151: 种树【贪心+堆】

和数据备份差不多 设二元组(i,a[i]),开一个大根堆把二元组塞进去,以len排序,每次取出一个二元组 因为单纯的贪心是不行的,所以设计一个"反悔"操作. 记录二元组的前驱pr后继ne,把拿出来的二元组的len加进答案,然后把当前二元组和它的前驱后继当成一个,也就是len[x]=a[pr[x]]+a[ne[x]]-a[x],相应修改前驱后继,然后"删掉"前驱后继的二元组,这样的意思是如果再次选了修改过的二元组x,就意味着退还掉x,选择它的前驱后继,易证这样个数和a

种树(贪心)

2151: 种树 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 714  Solved: 397[Submit][Status][Discuss] Description A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树.园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n.并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度.但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i

bzoj 1150&amp;2151&amp;2288(双向链表+堆)(贪心)

经典模型:在n个点中选k个点,要求两两不相邻,且总权值最大/最小. 做法:用双向链表串起来,把所有点丢进堆里,选择一个点的时候把它左右两个点从双向链表和堆中去除,然后把这个点的权值加进ans,出堆后改为左右两边的权值-当前权值重新入堆,重复k次,ans即为答案 原理:左右两边的权值-当前权值相当于这个点不选,改为选左右两边的点,并且多选了一个点,重复k次后必然取到k个点 三道同类型题 bzoj1150:显然一段网线肯定接在相邻的两个点,于是把相邻的点的距离求出来,问题就变成经典模型了 #incl

【BZOJ 1150】 1150: [CTSC2007]数据备份Backup (贪心+优先队列)

1150: [CTSC2007]数据备份Backup Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣.已知办公 楼都位于同一条街上.你决定给这些办公楼配对(两个一组).每一对办公楼可以通过在这两个建筑物之间铺设网 络电缆使得它们可以互相备份.然而,网络电缆的费用很高.当地电信公司仅能为你提供 K 条网络电缆,这意味 着你仅

BZOJ 1089 严格n元树 (递推+高精度)

题解:用a[i]表<=i时有几种树满足度数要求,那么这样就可以递归了,a[i]=a[i-1]^n+1.n个节点每个有a[i-1]种情况,那么将其相乘,最后加上1,因为深度为0也算一种.那么答案就是a[n]-a[n-1].然后就是高精度的问题了,发现很久没有现码高精度没手感了,连高进度加法进位都出了些问题,需要特别注意. #include <cstdio> #include <cstring> #include <algorithm> using namespace

【bzoj2151】种树(堆/优先队列+双向链表)

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2151 这道题因为优先队列不怎么会用,而且手写堆的代码也不长,也想复习一下手写堆的写法……结果……WAWAWAWAW……看来我对堆的认识还是太浅薄了…… 这道题,如果没有限制不能选相邻的两个位置,那就肯定是贪心地选择m个美观度最大的位置种树.然而这里加了限制,那么我们可以注意到,如果一个美观度比较大的位置不被选上,一定是因为它两边的位置都被选了. 于是我们可以把n个美观度压进一个堆里,每