HDU 5289 Assignment(单调队列)

本文详细解析了使用单调队列解决区间能力差问题的方法,并提供了两种实现方式:一种是普通单调队列,另一种是结合了二分查找的单调队列。通过这两种方式,有效地解决了在给定数组中寻找符合特定条件的子数组数量的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给T足数据,然后每组一个n和k,表示n个数,k表示最大允许的能力差,接下来n个数表示n个人的能力,求能力差在k之内的区间有几个


分析:维护一个区间的最大值和最小值,使得他们的差小于k,于是采用单调队列


普通单调队列做法:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 1e6+5;
int a[maxn];
struct node{
    int index;
    int v;
}qd[maxn];
node qx[maxn];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        int st1,st2,ed1,ed2;
        st1=st2=ed1=ed2=1;
        long long sum=0;
        int j=1;
        for(int i=1;i<=n&&j<=n;i++){        
            if(i==1){
                qd[1].index=qx[1].index=1;
                qd[1].v=qx[1].v=a[1];
            }
            else{
                while(st1<=ed1){                //单调队列维护最大值
                    if(qd[ed1].v<=a[i]) ed1--;  //比a[i]小的而且下标比i小的出队列
                    else break;
                }
                qd[++ed1].v=a[i];               //a[i]入队列
                qd[ed1].index=i;
                while(st2<=ed2){                //单调队列维护最小值
                    if(qx[ed2].v>=a[i]) ed2--;  //比a[i]大而且下标比i小的出队列
                    else break;
                }
                qx[++ed2].v=a[i];               //a[i]入队列
                qx[ed2].index=i;
                while(qd[st1].v-qx[st2].v>=k&&st1<=ed1&&st2<=ed2)   //计数
                {
                    if(qd[st1].index==j) st1++;
                    if(qx[st2].index==j) st2++;
                    sum+=(i-j);
                    j++;
                }
            }
        }
        while(j<=n) {
            sum+=(n-j+1);
            j++;
        }
        printf("%I64d\n",sum);
    }
}

二分单调队列做法:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 1e6+5;
int a[maxn];
struct node{
    int index;
    int v;
}qd[maxn];
node qx[maxn];
int maxc(int l,int r,int d){        //二分找出d入队列的为止
    while(l<=r){
        int mid=(l+r)/2;
        if(qd[mid].v==d) return mid;
        else if(qd[mid].v>d) l=mid+1;
        else r=mid-1;
    }
    return l;
}
int minc(int l,int r,int d){        //二分找出d入队列的为止
    while(l<=r){
        int mid=(l+r)/2;
        if(qx[mid].v==d) return mid;
        else if(qx[mid].v<d) l=mid+1;
        else r=mid-1;
    }
    return l;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        int st1,st2,ed1,ed2;
        st1=st2=ed1=ed2=1;
        long long sum=0;
        int j=1;
        for(int i=1;i<=n&&j<=n;i++){
            if(i==1){
                qd[1].index=1;
                qd[1].v=a[1];
                qx[1].index=1;
                qx[1].v=a[1];
            }
            else{
                ed1=maxc(st1,ed1,a[i]); //二分找出d入队列的为止,维护最大值
                qd[ed1].v=a[i];         
                qd[ed1].index=i;
                ed2=minc(st2,ed2,a[i]); //二分找出d入队列的为止,维护最小值
                qx[ed2].v=a[i];
                qx[ed2].index=i;
                while(qd[st1].v-qx[st2].v>=k&&st1<=ed1&&st2<=ed2)//计数
                {
                    if(qd[st1].index==j) st1++;
                    if(qx[st2].index==j) st2++;
                    sum+=(i-j);
                    j++;
                }
            }
        }
        while(j<=n) {
            sum+=(n-j+1);
            j++;
        }
        printf("%I64d\n",sum);
    }
}



HDU 3732 (Queue) 是一个经典的队列操作题目,在这个题目的设定下,你需要处理一系列关于入队、出队的操作,并最终输出特定的结果。这类问题通常会涉及到数据结构中的“队列”这一概念。 ### 题目概述 在 HDU 3732 中,你将面对的是一个标准的队列入栈和出栈的问题变种。它可能会给出一些序列化的指令集,包括: - 入队(push) - 出队(pop) 并且最后询问某些元素的状态或顺序等信息。 ### 解决思路 为了应对这个问题,你可以采用双端队列的数据结构或者两个栈模拟队列的方式来解决问题。以下是具体的步骤: 1. **初始化**:创建所需的辅助变量及容器,如 `queue` 或者一对用于模拟队列行为的栈 (`stackIn`, `stackOut`)。 2. **处理命令流**:遍历输入命令列表,根据不同类型的命令做相应动作: - 对于每一个 push 操作直接添加到指定位置; - 当遇到 pop 命令,则从头部移除元素;如果是用栈实现的话需要特殊处理,比如先全部倒入另一个栈再弹出顶部元素作为当前最先进来的那个值被移走。 3. **生成结果**:按照题目要求整理并返回正确的输出内容。 4. **注意事项** - 确保每次只对有效范围内的索引执行插入/删除操作。 - 考虑边界条件,例如空队列出队等情况下的异常处理。 ### 示例代码片段(Python 实现) ```python from collections import deque def process_queue_commands(commands): queue = deque() for command in commands: if "in" == command[0]: value = int(command.split()[1]) queue.append(value) elif "out" == command and len(queue)>0: print("Pop element:", queue.popleft()) # 示例用法 commands = ["5", "in 8", "in 9", "out"] process_queue_commands(commands[1:]) ``` 请注意实际比赛中给定的具体细节可能有所差异,请参考原题描述进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值