BZOJ3831: [Poi2014]Little Bird

看上去像是个单调队列

怎么选出 min{f_j + [h_i >= h_j]} 呢

只要保证从 f 值最小的里面选出 h 最大的就好了

由于 h 带来的差异最多是 1,所以可以直接上单调队列

push 元素的时候比队尾优的条件就是 f[i] < f[tail] 或 (f[i] == f[tail] 且 h[i] >= h[tail])


 代码:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cstdio>
#include <queue>
using namespace std;

const int MAX_N = 1000005;

int n, m, k, hd, tl;
int h[MAX_N], f[MAX_N], q[MAX_N];

inline int rd() {
	register int x = 0, c = getchar();
	while (!isdigit(c)) c = getchar();
	while (isdigit(c)) {
		x = x * 10 + (c ^ 48);
		c = getchar();
	}
	return x;
}
inline void dp() {
	hd = 1; tl = 0;
	f[1] = 0;
	q[++tl] = 1;
	for (int i = 2; i <= n; ++i) {
		while (hd <= tl && i - q[hd] > k) ++hd;
		f[i] = f[q[hd]] + (h[i] >= h[q[hd]]);
		while (hd <= tl && ((f[q[tl]] > f[i]) || (f[q[tl]] == f[i] && h[i] >= h[q[tl]]))) --tl;
		q[++tl] = i;
	}
	printf("%d\n", f[n]);
}

int main() {
	n = rd();
	for (int i = 1; i <= n; ++i) h[i] = rd();
	m = rd();
	while (m--) {
		k = rd();
		dp();
	}
	return 0;
}
posted @ 2018-11-01 09:21  EvalonXing  阅读(152)  评论(0编辑  收藏  举报