DP方程
f[i] = f[j] + (a[j] <= a[i]) ( i - k < j < i )
要使 f[i] 最小,需要等号后面的值最小,可以用单调队列来维护。
至于如何维护,具体看代码。
——代码
1 #include <cstdio> 2 3 const int MAXN = 1000005; 4 int n, k, Q, h, t; 5 int a[MAXN], q[MAXN], f[MAXN]; 6 7 inline bool cmp(int x, int y) 8 { 9 return f[x] > f[y] || (f[x] == f[y] && a[x] < a[y]); 10 } 11 12 int main() 13 { 14 int i; 15 scanf("%d", &n); 16 for(i = 1; i <= n; i++) scanf("%d", &a[i]); 17 scanf("%d", &Q); 18 while(Q--) 19 { 20 scanf("%d", &k); 21 f[q[1] = h = t = 1] = 0; 22 for(i = 2; i <= n; i++) 23 { 24 while(h <= t && q[h] < i - k) h++; 25 f[i] = f[q[h]] + (a[q[h]] <= a[i]); 26 while(h <= t && cmp(q[t], i)) t--; 27 q[++t] = i; 28 } 29 printf("%d ", f[n]); 30 } 31 return 0; 32 }
总结
这个题告诉我们,单调队列的单调性不仅仅只是个 < 或 > ,单调性是要满足最优解在一定在最前面。