一眼看上去这个题就要DP,可是应该怎么DP呢,我们发现,数据范围最多支持O(NlogN),但是这种DP貌似不怎么有,所以应该是O(N)算法,自然想到单调队列优化DP。
然后我们先考虑如果不用单调队列应该怎么转移,那么f[i]=min(f[k]) (i-k>m)+(a[k]<=a[i])。而min(f[k])可以用单调队列求出。
然后就是之后的几个错误点:
1.一定不能看反不等号的方向。。
2.队头要先设置为1,此题因为可以事先直接入队第一个所以把队尾也设置成1.
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #define re register #define wc 0.0000000001 using namespace std; int f[1000001],a[1000001],s[1000001],ans,m,n,x,q[2000001]; int main() { cin>>n; for(re int i=1;i<=n;i++) { cin>>a[i]; s[i]=s[i-1]+a[i]; } cin>>m; for(re int i=1;i<=m;i++) { cin>>x; f[1]=0; int h=1,t=1; q[t]=1; for(re int j=2;j<=n;j++) { while(h<=t&&j-q[h]>x) h++; f[j]=f[q[h]]+(a[q[h]]<=a[j]); while(h<=t&&(f[j]<f[q[t]]||(f[j]==f[q[t]]&&a[j]>=a[q[t]]))) t--; q[++t]=j; } cout<<f[n]<<endl; } }