luogu 传送门https://www.luogu.com.cn/problem/P3572
解题思路
先设 表示到 的最小劳累值。
很容易得出转移:
其中 由 和 的大小关系决定,并且 。
很显然,直接暴力是 的,会超时。
于是,考虑优化。
我们发现 是有一定的取值范围,并且我们取的是这个区间内的最小值。
也许这可以用单调队列优化。
判断对头是否在范围内,如果不在即出队;
入队的时候,考虑队尾的劳累值是否大于当前的劳累值,如果大于,则队尾出队,如果队尾的劳累值等于当前的劳累值,我们可以比较谁的高度更高,保留更高的(因为更高的对后面的情况更优)。
于是,时间复杂度降为
代码
#include<bits/stdc++.h>
using namespace std;
int n;
int d[1000001];
int qi;
int ki;
int f[1000001];
int q[1000001];
int head,tail;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>d[i];
}
cin>>qi;
while(qi--)
{
cin>>ki;
head=1,tail=0;
f[1]=0;
q[++tail]=1;
for(int i=2;i<=n;i++)
{
while(head<=tail&&q[head]<i-ki)
head++;
if(d[i]>=d[q[head]])
f[i]=f[q[head]]+1;
else
f[i]=f[q[head]];
while(head<=tail&&(f[q[tail]]>f[i]||(f[q[tail]]==f[i]&&d[q[tail]]<=d[i])))
tail--;
q[++tail]=i;
}
cout<<f[n]<<endl;
}
return 0;
}