背景:
逃物理竞赛
+
2
+2
+2。
题目传送门:
https://www.luogu.org/problemnew/show/P3572
题意:
一个序列,每一次选择大于等于当前的数时,贡献加
1
1
1,求每一次走规定距离时的最小贡献。
思路:
大水题。
f
i
f_i
fi表示到
i
i
i的最小贡献。
因为我们要使贡献尽可能小,所以
f
f
f要小;若
f
f
f相等,则高度尽可能大(因为可能使后面少往上跳)。
若队列的跨度大于给定的范围,弹出队首即可。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,q;
int a[1000010],que[1000010],f[1000010];
int work(int x)
{
int head=1,tail=1;
que[1]=1;
f[1]=0;
for(int i=2;i<=n;i++)
{
while(head<=tail&&i-que[head]>x) head++;
f[i]=f[que[head]]+(a[que[head]]<=a[i]);
while(head<=tail&&((f[i]<f[que[tail]])||(f[i]==f[que[tail]]&&a[i]>=a[que[tail]]))) tail--;
que[++tail]=i;
}
return f[n];
}
int main()
{
int x;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
scanf("%d",&x);
printf("%d\n",work(x));
}
}