入门

单调队列的性质:
(1):队列中的元素是单调的
(2):队尾插入元素,队首队尾删除元素
应用:求静态区间最值

裸单调队列
Description
An array of size n ≤ 10 6 is given to you. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves rightwards by one position. Following is an example:
The array is [1 3 -1 -3 5 3 6 7], and k is 3.
Window position Minimum value Maximum value
[1 3 -1] -3 5 3 6 7 -1 3
1 [3 -1 -3] 5 3 6 7 -3 3
1 3 [-1 -3 5] 3 6 7 -3 5
1 3 -1 [-3 5 3] 6 7 -3 5
1 3 -1 -3 [5 3 6] 7 3 6
1 3 -1 -3 5 [3 6 7] 3 7
Your task is to determine the maximum and minimum values in the sliding window at each position.
Input
The input consists of two lines. The first line contains two integers n and k which are the lengths of the array and the sliding window. There are n integers in the second line.
Output
There are two lines in the output. The first line gives the minimum values in the window at each position, from left to right, respectively. The second line gives the maximum values.
Sample Input
8 3
1 3 -1 -3 5 3 6 7
Sample Output
-1 -3 -3 -3 3 3
3 3 5 5 6 7

题意:n个数,窗口长度为k,求[i,i+k-1]中的最大值和最小值。

做法:以最大值为例,维护一个单调递减的队列,先把前k个数入队,然后遍历k到n的数,分别维护队尾和队首,维护队尾是保证队列的单调性,维护队首是保证队首元素的下标不小于i-k+1,因为队首元素代表[i-k+1,i]这个区间的最大值

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 1000005;
int a[maxn],mi[maxn],mx[maxn],n,k;
struct node
{
    int x,y;
}q[maxn];

void Getmin()
{
    int i,head = 1,tail = 0;
    for(i=1; i<k; i++)
    {
        while(head <= tail && q[tail].x >= a[i])//队列不为空且队尾元素大于等于当前元素就要出队,直到队列为空或者队尾元素小于当前元素
            tail--;
        q[++tail].x = a[i];
        q[tail].y = i;
    }
    for(;i<=n; i++)
    {
        while(head <= tail && q[tail].x >= a[i])//维护队尾
            tail--;
        q[++tail].x = a[i];
        q[tail].y = i;
        while(q[head].y < i-k+1)//维护队首
            head++;
        mi[i-k+1] = q[head].x;
    }
}

void Getmax()
{
    int i,head = 1,tail = 0;
    for(i=1; i<k; i++)
    {
        while(head <= tail && q[tail].x <= a[i])
            tail--;
        q[++tail].x = a[i];
        q[tail].y = i;
    }
    for(;i<=n; i++)
    {
        while(head <= tail && q[tail].x <= a[i])
            tail--;
        q[++tail].x = a[i];
        q[tail].y = i;
        while(q[head].y < i-k+1)
            head++;
        mx[i-k+1] = q[head].x;
    }
}

int main()
{
   scanf("%d%d",&n,&k);
   for(int i=1; i<=n; i++)
   {
       scanf("%d",&a[i]);
   }
   Getmin();
   Getmax();
   for(int i=1; i<=n-k+1; i++)
   {
       printf("%d ",mi[i]);
   }
   printf("\n");
   for(int i=1; i<=n-k+1; i++)
   {
       printf("%d ",mx[i]);
   }
}

单调队列的灵活应用
Description
Pxt每过一段时间都会更换各个社交账号的密码。密码当然不能明文存储,Pxt随意写下了若干个n位16进制整数,一则k位的密码是将该数保留k位且相对位置不变的最大16进制数。

Pxt现在要去睡午觉,请你帮助他完成密码生成器。

Standard Input
包含多组测试数据。

每组测试数据,第一行是两个整数n,k,含义如题目所示。

第二行包含一个n位16进制整数,字母小写,n位数以空格分隔。

Standard Output
每组数据输出一行表示Pxt的k位密码。(不含空格)

Samples
Input

4 2
9 a b c
6 3
1 a 2 b 3 c
Output
bc
b3c
Constraints
n,k≤100,000n,k≤100,000

Note
数据加强,注意数据范围 存在k=0

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 100005;
char s[maxn],t[maxn];
int main()
{
    int n,k;
    while(scanf("%d%d",&n,&k) != EOF)
    {
        for(int i=0; i<n; i++)
        {
            cin>>s[i];
        }
        int i;
        deque<char>q;
        for(i=0; i<n-k+1; i++)
        {
            while(!q.empty() && s[i] > q.front())
                q.pop_front();
            q.push_front(s[i]);
        }
        int j = 0;
        t[j++] = q.back();
        q.pop_back();
        for(; i<n; i++)
        {
            while(!q.empty() && s[i] > q.front())
                q.pop_front();
            q.push_front(s[i]);
            t[j++] = q.back();
            q.pop_back();
        }
        for(int i=0; i<k; i++)
        {
            printf("%c",t[i]);
        }
        printf("\n");
    }
}

描述:
老板需要你帮忙浇花。给出N滴水的坐标,y表示水滴的高度,x表示它下落到x轴的位置。

每滴水以每秒1个单位长度的速度下落。你需要把花盆放在x轴上的某个位置,使得从被花盆接着的第1滴水开始,到被花盆接着的最后1滴水结束,之间的时间差至少为D。

我们认为,只要水滴落到x轴上,与花盆的边沿对齐,就认为被接住。给出N滴水的坐标和D的大小,请算出最小的花盆的宽度W。
输入输出格式
输入格式:

第一行2个整数 N 和 D。

第2… N+1行每行2个整数,表示水滴的坐标(x,y)。
输出格式:
仅一行1个整数,表示最小的花盆的宽度。如果无法构造出足够宽的花盆,使得在D单位的时间接住满足要求的水滴,则输出-1。
输入样例#1:
4 5
6 3
2 4
4 10
12 15
输出样例#1:
2

题意:给出n个点的x、y值,找最小的区间(区间长度为端点的x值相减),使得区间上的点的y值的最大值和最小值的差大于等于D。

做法:尺取+单调队列维护区间最值。一个单调队列只能维护区间的最大值或最小值,所以要用两个单调队列来维护区间最值。单调递增队列的队首是区间最小值,单调递减队列的队首的区间最大值。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
using namespace std;
const int maxn = 1e6+5;
const int INF = 0x3f3f3f3f;

struct node
{
    int x,y,id;
}a[maxn];

bool cmp(node a,node b)
{
    if(a.x != b.x)
        return a.x < b.x;
    else
        return a.y < b.y;
}

int main()
{
    int n,d;
    scanf("%d%d",&n,&d);
    for(int i=1; i<=n; i++)
        scanf("%d%d",&a[i].x,&a[i].y);
    sort(a+1,a+1+n,cmp);
    for(int i=1; i<=n; i++)
        a[i].id = i;
    deque<node> q1,q2;
    int r,ans = INF;
    q1.push_back(a[1]);
    q2.push_back(a[1]);
    r = 1;
    for(int i=1;i<=n;i++) {
        while(q1.front().id<i) q1.pop_front();
        while(q2.front().id<i) q2.pop_front();//这两句相当于枚举左端点
        while(r<n&&q2.front().y-q1.front().y<d) {//右端点不符合条件就一直++
            r++;
            while(!q2.empty()&&q2.back().y<=a[r].y) {
                q2.pop_back();
            }
            q2.push_back(a[r]);
            while(!q1.empty()&&q1.back().y>=a[r].y) {
                q1.pop_back();
            }
            q1.push_back(a[r]);
        }
        if(q2.front().y-q1.front().y<d) break;
        ans=min(ans,a[r].x-a[i].x);
    }
    if(ans==INF) puts("-1"); else
    printf("%d\n",ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值