• 算法笔记:单调队列


    考试考了两遍单调队列 第一遍不懂,第二遍没满分(郁闷)
    单调队列可以用来优化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
    ",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
    ",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;
    }
    
  • 相关阅读:
    题目1007:奥运排序问题(自定义排序问题)
    题目1005:Graduate Admission(录取算法)
    九度OJ小结2
    题目1049:字符串去特定字符(简单字符判断)
    题目1111:单词替换(字符串查找)
    题目1168:字符串的查找删除(字符串操作)
    题目1455:珍惜现在,感恩生活(多重背包问题)
    题目1454:Piggy-Bank(完全背包问题)
    题目1453:Greedy Tino(dp题目)
    题目1452:搬寝室(dp题目)
  • 原文地址:https://www.cnblogs.com/Steinway/p/9239464.html
Copyright © 2020-2023  润新知