算法笔记:单调队列

考试考了两遍单调队列 第一遍不懂,第二遍没满分(郁闷)
单调队列可以用来优化dp,但是我这次只学了区间和的优化(毕竟叫笔记 dp的坑就不填了)(其实是懒)

因为单调队列非常简单(虽然我就是看不懂)
所以我这里就放三个题的代码供思考(基本囊括所有的板子)

1:最大字段和

描述

输入一个长度为n的整数序列,从中找出一段不超过m的连续子序列,使得整个序列的和最大。

例如 1,-3,5,1,-2,3

当m=4时,S=5+1-2+3=7
当m=2或m=3时,S=5+1=6

输入格式

第一行两个数n,m(n,m<=300000)
第二行有n个数,要求在n个数找到最大子序和

输出格式

一个数,数出他们的最大子序和

样例输入

6 4
1 -3 5 1 -2 3

样例输出

7

代码

//#define fre yes

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 300005;
int q[maxn];
int sum[maxn];

int n,m,ans=-1e9;

template<typename T>inline void read(T&x)
{
    x = 0;char c;int lenp = 1;
    do { c = getchar();if(c == '-') lenp = -1; } while(!isdigit(c));
    do { x = x * 10 + c - '0';c = getchar(); } while(isdigit(c));
    x *= lenp;
}

int main()
{
    read(n);read(m);
    for (int i=1;i<=n;i++)
    {
        int x;
        read(x);
        sum[i] = sum[i-1] + x;
    }

    int l = 1,r = 1;
    q[1] = 0;
    for (int i=1;i<=n;i++)
    {
        while(l<=r && q[l] < i - m) l++;
        ans = max(ans,sum[i] - sum[q[l]]);
        while(l<=r && sum[q[r]] >= sum[i]) r--;
        q[++r] = i;
    } printf("%d\n",ans);
    return 0;
}


2:扫描

题目描述

有一个 1 ∗ n 的矩阵,有 n 个正整数。

现在给你一个可以盖住连续的 k 的数的木板。

一开始木板盖住了矩阵的第 1 ∼ k 个数,每次将木板向右移动一个单位,直到右端与

第 n 个数重合。

每次移动前输出被覆盖住的最大的数是多少。

输入格式:

从 scan.in 中输入数据

第一行两个数,n,k,表示共有 n 个数,木板可以盖住 k 个数。

第二行 n 个数,表示矩阵中的元素。

输出格式:

输出到 scan.out 中

共 n − k + 1 行,每行一个正整数。

第 i 行表示第 i ∼ i + k − 1 个数中最大值是多少。

输入样例#1:

5 3
1 5 3 4 2

输出样例#1:

5
5
4

说明

对于 20% 的数据保证:1 ≤ n ≤ 1e3,1 ≤ k ≤ n

对于 50% 的数据保证:1 ≤ n ≤ 1e4,1 ≤ k ≤ n

对于 100% 的数据保证:1 ≤ n ≤ 2 ∗ 1e6,1 ≤ k ≤ n

矩阵中元素大小不超过 1e4。

代码

//#define fre yes

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 1000005;
int a[maxn];
int q[maxn];
int ans[maxn];

int n,K;

template<typename T>inline void read(T&x)
{
    x = 0;char c;int lenp = 1;
    do { c = getchar();if(c == '-') lenp = -1; } while(!isdigit(c));
    do { x = x * 10 + c - '0';c = getchar(); } while(isdigit(c));
    x *= lenp;
}

int main()
{
    read(n);read(K);
    for(int i=1;i<=n;i++) read(a[i]);

    int l=1,r = 0;
    for(int i=1;i<=n;i++)
    {
        while(l<=r&&q[l]<=i-K)l++;
        while(l<=r&&a[i]>a[q[r]])r--;
        q[++r]=i;
        ans[i]=a[q[l]];
    }
    for(int i=K;i<=n;i++)printf("%d\n",ans[i]);
    return 0;
}



3.滑动的窗户

题目描述

在一个包含 n 个元素的数组上,有一个长度为 k 的窗户在从左向右滑动。窗户每滑动到一个位置,我们都可以看到 k 个元素在窗户中。如下的例子所示,假设数组为 [1 3 -1 -3 5 3 6 7],而 k 等于 3 :

窗户位置 最小值 最大值
[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

对于窗户滑动过的每个位置,请给出窗户内 k 个元素的最小值和最大值。

输入格式:

输入的第一行包括两个整数 n,k ,n 表示数组的长度,k 表示窗户的长度。
接下来一行包括 n 个整数,表示这个 n 个元素的数组。

输出格式:

输出包含两行,每行包括 n-k+1 个整数。
第一行表示窗户从左到右滑动过程中的最小值。
第二行表示窗户从左到右滑动过程中的最大值。

样例输入:

8 3 
1 3 -1 -3 5 3 6 7 

样例输出:

-1 -3 -3 -3 3 3 
3 3 5 5 6 7 

数据范围:

对于 100% 的数据,3<=n<=1000000,1<=k<=n,数组中的每个元素均在 int 范围内。

附代码:

//#define fre yes

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 1000010;
int arr[maxn];

int summax[maxn],p[maxn],hub[maxn],h=1,t=0;
int summin[maxn],q[maxn],num[maxn],l=1,r=0;

int n,m;

template<typename T>inline void read(T&x)
{
    x = 0;char c;int lenp = 1;
    do { c = getchar();if(c == '-') lenp = -1; } while(!isdigit(c));
    do { x = x * 10 + c - '0';c = getchar(); } while(isdigit(c));
    x *= lenp;
}

int main()
{
    read(n);read(m);
    for(int i=1;i<=n;i++)
    {
        read(arr[i]);
        
        while(num[l]<=i-m) l++;
        while(q[r]>=arr[i]&&r>=l) r--;
        q[++r]=arr[i]; 
        num[r]=i;
        summin[i]=q[l];
        
        while(hub[h]<=i-m) h++;
        while(p[t]<=arr[i]&&t>=h) t--;
        p[++t]=arr[i];
        hub[t]=i;
        summax[i]=p[h];
    }

    for(int i=m;i<=n;i++) printf("%d ",summin[i]); puts("");
    for(int i=m;i<=n;i++) printf("%d ",summax[i]); puts("");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Steinway/p/9239464.html