1. 程式人生 > 實用技巧 >bzoj bzoj 3831 Little Bird 單調佇列優化DP

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\n", 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;
}