2021-7-8 单调队列及其应用

不是优先队列!不是优先队列!

我是fw呜呜呜!看了好久了!

单调队列是既是单调,同时也符合队列先进先出的特点。(入队顺序在前的元素不能排到入队顺序在后的元素后面,而且队内元素有单调性)

假设要求队列都必须是单调递增的数字,而且入队顺序是固定的:
入队顺序:
1 3 2 4 5

队列:
1
1 3
1 2(重点在这步,当要入队的数字不符合递增的条件,那么就让它持续向前走,并删除其后面的元素。)
1 2 4
1 2 4 5

最基础的例题:
求m区间内的最小值

const int maxn=2e6+7;

int a[maxn];
int dl[maxn];
int idx[maxn];
int le=1,ri=0;

int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=n;i++){
        cout<<dl[le]<<endl;//队首维护的是合法区间内最小值
        while(le<=ri&&a[i]<dl[ri]){
            //删除不应该出现在队列中的元素(不可能成为答案的元素)
            ri--;
        }
        dl[++ri]=a[i];//新元素入队
        idx[ri]=i;
        if(i-idx[le]>=m) le++;//如果区间的左边界不在符合条件,则令队头出队
    }
}

多重背包的单调队列优化:

//单调队列优化多重背包

const int maxn=2e4+7;
ll last[maxn];
ll now[maxn];

//单调队列
ll q[maxn];


int main(){
    int N,V;
    cin>>N>>V;
    for(int i=1;i<=N;i++){
        ll v,w,s;
        cin>>v>>w>>s;
        memcpy(last,now,sizeof last);
        for(int j=0;j<v;j++){
            int h=1,t=0;//单调队列头与尾
            for(int k=j;k<=V;k+=v){
                //不能用的队头出队列
                if(h<=t&&q[h]<k-s*v){
                    h++;
                }
                //运用队头更新now
                if(h<=t){
                    now[k]=max(last[k],last[q[h]]+((k-q[h])/v)*w);
                }
                //不符合就往前移
                while(h<=t&&last[q[t]]+(k-q[t])/v*w<=last[k]){
                    t--;
                }
                //下标入队列
                q[++t]=k;
            }
        }
    }
    ll ans=0;
    for(int i=0;i<=V;i++){
        ans=max(ans,now[i]);
    }
    cout<<ans<<endl;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KaaaterinaX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值