【P3572】little bird(单调队列+DP)

一眼看上去这个题就要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;
    }
} 
原文地址:https://www.cnblogs.com/victorique/p/8426784.html