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;
}