题解:
其实是一个神奇的贪心。如果m > n / 2,那么显然无解,否则肯定有解。如果没有相邻不能取的限制,那么直接贪心取前m大即可,但是有这个限制。所以考虑怎么维护这个性质。
首先有一个结论,如果是贪心的取,对于一个点,要么取它旁边的两个,因为是贪心的取的,如果只取了旁边中的一个的话,那还不如就取它自己,而不取旁边的,因为只取旁边的一个肯定比取它小,还不会干扰别的树的取舍。
那么基于这个结论,可以观察到,如果取x,那么被限制不能取的树是x - 1和x + 1,如果取它两边的数,那就么被限制的就是x, x + 2, x - 2,而x在取x的时候就已经被限制不能取第二次了,也就是从取x转变为取x + 1和x - 1时,多出来的限制只有x - 2, x + 2,所以如果取出x后,就把x - 1, x + 1合并成一个节点,那么x + 2, x - 2就相当于是这个新节点的相邻节点,于是就可以再像取x时一样做了。而因为取了这个新的被融合的节点,我们就需要舍弃x这个节点,因此代价应该是w[x - 1] + w[x + 1] - w[x]。但被限制的标记应该要打在vis[x - 1]和vis[x + 1]上,因为被融合的新点是放在vis[x]的位置上的。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 201000 5 #define LL long long 6 int n, m, ans; 7 int a[AC], last[AC], Next[AC]; 8 bool z[AC]; 9 10 struct node{ 11 int w, id; 12 }; 13 14 struct cmp{ 15 bool operator () (node a, node b) 16 { 17 return a.w < b.w; 18 } 19 }; 20 21 priority_queue<node, vector<node>, cmp> q; 22 23 inline int read() 24 { 25 int x = 0; char c = getchar(); bool z = false; 26 while(c > '9' || c < '0') 27 { 28 if(c == '-') z = true; 29 c = getchar(); 30 } 31 while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); 32 if(!z) return x; 33 else return -x; 34 } 35 36 void pre() 37 { 38 n = read(), m = read(); 39 if(m > n / 2) 40 { 41 printf("Error! "); 42 exit(0); 43 } 44 for(R i = 1; i <= n; i ++) a[i] = read(); 45 } 46 47 void build() 48 { 49 for(R i = 1; i <= n; i ++) 50 { 51 node x = (node){a[i], i}; 52 last[i] = i - 1, Next[i] = i + 1; 53 if(!last[i]) last[i] = n; 54 if(Next[i] == n + 1) Next[i] = 1; 55 q.push(x); 56 } 57 } 58 59 void change(int x) 60 { 61 z[x] = true; 62 Next[last[x]] = Next[x], last[Next[x]] = last[x]; 63 Next[x] = last[x] = 0;//更新新坑周围的坑的前驱和后继 64 } 65 66 void work() 67 { 68 node x; 69 for(R i = 1; i <= m; i ++) 70 { 71 while(z[q.top().id]) q.pop();//因为选了一个点之后,这个点旁边的两个点被标记,于是旁边的就不能选了,但是这个点可以再选一次 72 x = q.top(); 73 q.pop(); 74 ans += x.w; 75 int l = last[x.id], r = Next[x.id];//error!!!是x.id不是i啊。。。。 76 a[x.id] = a[l] + a[r] - a[x.id];//相当于合并了3个坑 77 node now = (node){a[x.id], x.id}; 78 change(l), change(r); 79 q.push(now); 80 } 81 printf("%d ", ans); 82 } 83 84 int main() 85 { 86 // freopen("in.in", "r", stdin); 87 pre(); 88 build(); 89 work(); 90 // fclose(stdin); 91 return 0; 92 }