[NOIP2017普及组]跳房子(二分答案+单调队列优化dp)
确实算是板子题,不难发现“二分花费,dp 求最大得分”的 \(\mathcal{O(n\log n)}\) 思路,那么式子就是:
\[f_{i}=\max\limits_{x_i-x_j\in [L,R]}\{f_j+s_i\} \]其中 \(L=\max(1,d-g),R=d+g\)。显然符合单调队列性质。
但是在代码实现上出现了一点困难:判断 \(x_i-x_j>R\) 弹队头比较简单,如何限制 \(x_i-x_j
平时遇到较多的是 \(\max\limits_{i-k\le j 型的单调队列,没有见过在右侧加以限制的类型,还是做题太少了……
具体代码如下:
inline bool check(int g){
int l=1,r=0,L=std::max(1,d-g),R=d+g;
memset(f,0xcf,sizeof f);
f[0]=0;
for(int i=1,j=0;i<=n;++i){
while(j<=n&&x[i]-x[j]>=L){
while(l<=r&&f[q[r]]<=f[j]) --r;
q[++r]=j,++j;
}
while(l<=r&&x[i]-x[q[l]]>R) ++l;
if(l<=r) f[i]=f[q[l]]+s[i];//不再立即进队,而是改为在上方while处等待
if(f[i]>=k) return 1;
}
return 0;
}