bzoj bzoj 3831 Little Bird 单调队列优化DP bzoj 3831 Little Bird

题目链接

​ 单调队列优化DP。

​ 设(f[i])表示从1到(i)的最少步数,那么转移方程很好想:(f[i] = a[i] < a[h] ? f[h] : f[h] + 1)

​ 主要是得用单调队列优化,考场上我傻乎乎的写了个线段树优化,时间根本没降下来,还挺难码。。。

​ 将(f[i])压入队尾的时候,如果(f)值相同,那么把更高的放进去。

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
	long long s = 0, f = 1; char ch;
	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
	return s * f;
}

const int N = 1e6 + 5, inf = 1e9;
int n, m;
int q[N], h[N], f[N];

void work(int k) {
	int l = 1, r = 1;
	q[1] = 1;
	for(int i = 2;i <= n; i++) {
		while(l <= r && i - q[l] > k) l++;
		if(h[i] < h[q[l]]) f[i] = f[q[l]];
		else f[i] = f[q[l]] + 1;
		while(l <= r && (f[q[r]] > f[i] || (f[q[r]] == f[i] && h[q[r]] <= h[i]))) r--;
		q[++r] = i;
	}
	printf("%d
", f[n]);
}

int main() {
	
	
	n = read();
	for(int i = 1;i <= n; i++) h[i] = read();
						
	m = read();
	for(int i = 1, k;i <= m; i++) k = read(), work(k);
	
	fclose(stdin); fclose(stdout);
	return 0;
}