little bird
LITTLE BIRD
Bzoj 3831
相对而言是一道比较简单的DP,不过它需要用单调队列优化。首先是朴素O(n2),
if(d[j]>f[i])
f[i]=min(f[i],f[j]);
else
f[i]=min(f[i],f[j]+1);
f[i]表示从1到i需要的最少代价
K很大时会很慢
1 #include<bits/stdc++.h> 2 3 #define INF 9999999 4 5 using namespace std; 6 7 int n,k; 8 9 int f[1000000]; 10 11 int d[1000000]; 12 13 int main() 14 15 { 16 17 cin>>n>>k; 18 19 memset(f,INF,sizeof(f)); 20 21 f[1]=0; 22 23 for(int i=1;i<=n;i++) 24 25 cin>>d[i]; 26 27 for(int i=1;i<=n;i++) 28 29 { 30 31 for(int j=i-k;j<i;j++) 32 33 { 34 35 if(d[j]>d[i]) 36 37 f[i]=min(f[i],f[j]); 38 39 else 40 41 f[i]=min(f[i],f[j]+1); 42 43 } 44 45 } 46 47 cout<<f[n]; 48 49 return 0; 50 51 }
然后是单调队列优化,O(n)的复杂度,对于两个位置i、j,i在j之后,如果f[i]<f[j],直接抛弃j,如果f[i]==f[j],那再h[i]>=h[j],也是抛弃j,即tail--,最后i入队。队列的单调性是单调递增的,每次取队首就可以了。
优化过后,果然很快。
#include<bits/stdc++.h> using namespace std; int top,tail,q[1000001]; int f[1000001]; int n,k; int d[1000001]; bool cmp(int f1,int h1,int f2,int h2) { return f1==f2?h1>=h2:f1<f2; } int main() { cin>>n>>k; for(int i=1;i<=n;i++) cin>>d[i]; q[top=tail=1]=1; for(int i=2;i<=n;i++) { while(top<=tail&&i-top>k)top++; f[i]=f[q[top]]+(d[i]>=d[q[top]]?1:0); while(top<=tail&&cmp(f[i],d[i],f[tail],d[tail]))tail--; q[++tail]=i; } cout<<f[n]; return 0; }