单调队列

最大子序和 单调队列

匿名 (未验证) 提交于 2019-12-02 23:49:02
最大子序和 Time Limit: 1 Sec Memory Limit: 256 MB Description 输入一个长度为n的整数序列,从中找出一段不超过m的连续子序列,使得整个序列的和最大。 例如 1,-3,5,1,-2,3 当m=4时,S=5+1-2+3=7 当m=2或m=3时,S=5+1=6。 Input 第一行两个数n,m(1<=n,m<=300000) 第二行有n个数,要求在n个数找到最大子序和。 Output 一个数,即最大子序和S(S值不超过long long int)。 Sample Input 6 4 1 -3 5 1 -2 3 Sample Output 7 分析: 所以只需要枚举j,并找到每段区间中的最小值s[i]即可 int n,m; cin>>n>>m; for(int i=1;i<=n;i++)scanf("%d",&a[i]),s[i] = s[i-1] + a[i]; //s[i] = a[1] + ... + a[i]; int l = 1,r = 1; // 维护队列左右边界 q[l] = 0;//q 单调队列 存下标 ans = -0xfffffff;// ans初始化为极小值 for(int i=1;i<=n;i++) { while(l<=r && q[l]<i-m) l++; ans = max(ans,s[i] - s[q[l]]

单调队列

匿名 (未验证) 提交于 2019-12-02 23:32:01
单调队列在求滑动窗口的时候用 例:给出一个长度为n的序列A,求A中所有长度为m的连续子序列的最大值 始终保持队列中的元素的个数为m 求最大值就单调递减队列 从头开始遍历每个位置 那么队头即为每个子序列的最大值 例题: Sliding Window 这个求最大和最小值 用两个双端队列 切记 能一个循环完事的就一个循环完事 #include <iostream> #include <cstdio> #include <sstream> #include <cstring> #include <map> #include <cctype> #include <set> #include <vector> #include <stack> #include <queue> #include <algorithm> #include <list> #include <cmath> #include <bitset> #define rap(i, a, n) for(int i=a; i<=n; i++) #define rep(i, a, n) for(int i=a; i<n; i++) #define lap(i, a, n) for(int i=n; i>=a; i--) #define lep(i, a, n) for(int i=n; i>a; i--) #define rd(a)

【数据结构】 队列

不打扰是莪最后的温柔 提交于 2019-12-02 06:50:35
一、介绍 队列是一种“先进先出”的 线性数据结构 。一般来讲,元素从右端进入队列( 入队 ), 从左端离开队列(出队)。于是我们称队列的左端为队头,右端为队尾。 例题入口 二、单调队列 在队列中维护一个单调性,换而言之让这个队列始终保持里面的元素拥有 单调递增/单调递减 的属性。 例题入口 来源: https://blog.csdn.net/qq_41280600/article/details/102733082

习题:小奇探险(单调队列 & dp)

前提是你 提交于 2019-12-02 03:33:01
题目 小奇去遗迹探险,遗迹里有 $N$ 个宝箱,有的装满了珠宝,有的装着废品。 小奇有地图,所以它知道每一个宝箱的价值,但是它不喜欢走回头路,所以要按顺序拿这 $N$ 个宝箱中的若干个。 拿宝箱很累的。一开始小奇的体力是 $1$,每得到一个宝箱之后,小奇得到的价值是体力 $\times$ 宝箱的价值,之后它的体力就会变为原来的 $k$ 倍 $(0<k<1)$。 小奇不喜欢连续放过很多宝箱,所以任意一段长度为 $M$ 的序列中,小奇一定要取走其中的一个宝箱。 现在小奇想知道它能得到的最大价值和。 第一行,两个整数 $N,M$,表示的含义如题目中所述; 第二行,一个小数 $k$,表示的含义如题目中所述,最多 $4$ 位小数; 第三行,$N$ 个整数,第 $i$ 个整数表示第 $i$ 个宝箱的价值。 输出一行,一个实数,表示小奇能得到的最大价值和,四舍五入保留两位小数。 思路 额。。。 考试之中的唯一一道水题 考虑从dp[i]转移到dp[i+k] 发现,转移需要考虑的要素太多,写起来太麻烦 但是如果从dp[i+k]转移到dp[i] 是不是简单了许多 $dp_i$表示前i号节点的最大值 $dp _i =max(dp_j*k+c_i,c_i) (i<j)$ 看到这个转移方程, 发现k为定值,c~i~也为定值 之后又单调队列进行优化就行了 代码 #include<iostream>

单调队列

你。 提交于 2019-12-01 20:14:06
单调队列(小)总结 最近,看到了自己洛谷任务计划队列中越堆越多,为了防止 咕咕咕 ,我就来写一写单调队列,清一清计划。 首先,我们先来看一道题: P1886 滑动窗口 。 题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。 例如: The array is [1 3 -1 -3 5 3 6 7], and k = 3。 输入格式 输入一共有两行,第一行为n,k。 第二行为n个数(x<INT_MAX) 输出格式 输出共两行,第一行为每次窗口滑动的最小值 第二行为每次窗口滑动的最大值。 输入输出样例 8 3 1 3 -1 -3 5 3 6 7 -1 -3 -3 -3 3 3 3 3 5 5 6 7 数据范围 50%的数据, \(n<=10^5\) 100%的数据, \(n<=10^6\) 这道题其实是属于单调队列的基础题,通过这道题就可以了解到单调队列。 法1:暴力法 我们可以考虑每一次滑动之后,我们枚举长度为k的序列,最后求出最大最小值。 当然,这样的时间复杂度 \((n*k)\) 是无法过掉这道题的。 法2:单调队列 我们可以来简单分析一下这个样例,这样更有助于我们理解单调队列。 {1,3,-1,-3,5,3,6,7} 首先,我们来看一下当k=3的时候的最小值。 [1,3

NOIP2017 跳房子(单调队列优化DP+二分)

限于喜欢 提交于 2019-12-01 12:55:32
50分做法: 可以发现答案具有单调性,所以二分答案。判断是否可行就需要DP。dp[i]表示到第i个格能得的最大值,从能跳向它的格进行转移即可。 #include<cstring> #include<algorithm> #include<cmath> #include<iostream> #include<cstdio> using namespace std; typedef long long ll; const int maxm=500007; int n,d,k; struct node { int x,z; }a[maxm]; int ans=-1; ll dp[maxm]; bool check(int x) { int maxx,minn; if(x<d) minn=d-x; else minn=1; maxx=d+x; memset(dp,-0x3f,sizeof(dp)); dp[0]=0; for(int i=1;i<=n;i++) { for(int j=0;j<=i-1;j++) { if((a[i].x-a[j].x)<minn||(a[i].x-a[j].x)>maxx) continue; dp[i]=max(dp[i],dp[j]+a[j].z); } } ll tot=-1e15; for(int i=0;i<=n;i++) { tot=max

PKU Campus 2015

两盒软妹~` 提交于 2019-12-01 07:21:46
# PKU Campus 2015 C.Rabbit's Festival 时间分治,并查集维护连通性 H.Lucky Draw 比赛期间被卡死了........... 一直以为带log肯定能过,然后换了n种姿势都T啦......... 标解单调队列,难点在于如何维护次小值(下面的讨论基定于把原序列翻转) 确定最小值后,次大值分为在该最小值前面或后面,如果在最小值后面,那普通的单调队列已能维护,但如果在该最小值前面,那再另开个单调队列维护小于我当前位置的最小值即可 I.The New MindSwitcher 第一次想了个鸡,每个环需要log次消除,然后wa半天 实际上两次就够了,第一次让所有大环拆为长度小于等于2的环,第二次绝杀即可 来源: https://www.cnblogs.com/FST-stay-night/p/11668174.html

浅谈单调队列优化DP

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-01 05:23:41
@ TOC 这篇是搬运自己在洛谷写的题解 题目链接: \(luoguP1725\) 相信读完题就能看出这是一道简单的DP题 状态转移 状态转移方程很容易想到。 即: dp[ i ] = max{区间内的最大dp值}+该点的权值 然而这种算法的最坏复杂度为$O(n^2)$,而本题的数据是$1e5$级别的,这样的复杂度显然不正确,必须优化。 优化 哪一步可以优化呢? 可以发现这样转移有着冗杂的枚举区间内元素的过程。 我们又发现每次跳的区间都是一个固定长度,自然而然地想到了一个经典的问题: 滑动窗口问题 ,即单调队列,可以让我们做到$O(n)$预处理,$O(1)$找到任意固定长度区间内的最值。 有了单调队列,我们的dp过程可以省去枚举区间内的每个元素的过程,总复杂度也由$O(n^2)$降到$O(n)$,完全没有压力。 如何实现 在代码中由注释进行讲解: #include<cstdio> using namespace std; #define oo 0x3f3f3f3f #define ri register int const int N = 200005; int n,l,r,head = 1,tail = 0,cur = 0,ans = -oo,a[N],q[N],dp[N]; //head,tail分别是单调队列的首尾指针,cur是指向当前待入队列的元素,a存权值,q为单调队列

poj2373(单调队列优化dp)

北城以北 提交于 2019-11-30 21:21:45
传送门 题意是每个洒水装置的半径范围为[A,B],每头奶牛有自己的一个区间[s,e],这个区间只能由一个洒水装置覆盖。 要求整个区间[1,L](L<=1e6)不重叠的被覆盖,最少要多少个洒水装置,洒水装置的范围不可以超过整体区间的范围。 因为一个区间[s,e]只能由一个洒水装置覆盖,所以[s+1,e-1]都不可能是某一个洒水装置洒水范围的右端点。 我们用not_r[]来打个标记。 看到L的范围1e6,我们知道应该是使用O(n)的算法。 设f[i]表示处理到i这个位置需要的洒水装置个数。(i一定是 右端点 )。 f[i]=min(f[j])+1(A<=(i-j)/2<=B) 直接循环时间O(n^2)考虑优化。 我们发现对于点i,可以用的j一定是一段连续的区间,所以单队维护最小的f[j]。 因为一个j能不能被使用还要看它的位置是否满足限制,所以用队列id存一下下标。 因为i是右端点,所以在循环的时候,我们是偶数个的增加。 #include<cstdio> #include<iostream> #include<cstring> #define LL long long #define INF 2100000000 #define N 1000003 #define re register using namespace std; int read() { int x=0,f=1

单调队列优化dp

六眼飞鱼酱① 提交于 2019-11-30 18:19:26
使用单调队列优化DP,那么必会有求i之前某个范围的极值的操作,这类DP的方程通常为: F[i]=min(F[j]+a[i]:j<i) (a[i]是与j无关的数。 定义:队列元素保持单调递增(减),而保持的方式就是通过插队,把队尾破坏了单调性的数全部挤掉,从而使队列元素保持单调 。 那么单调队列有什么用呢? 优化DP 。许多单调队列优化的DP可以使复杂度 直接降维 ,下面就以最简单的一道题为例: Description    烽火台又称烽燧,是重要的军事防御设施,一般建在险要或交通要道上。一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息;夜晚燃烧干柴,以火光传递军情 (晓荣的历史课讲过吼),在某两座城市之间有 n 个烽火台,每个烽火台发出信号都有一定代价。为了使情报准确地传递,在连续 m 个烽火台中至少要有一个发出信号。请计算总共最少花费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确传递。 Input   第一行:两个整数 N,M。其中N表示烽火台的个数, M 表示在连续 m 个烽火台中至少要有一个发出信号。接下来 N 行,每行一个数 Wi,表示第i个烽火台发出信号所需代价。 Output   一行,表示答案。 Sample Input 5 3 1 2 5 6 2 Sample Output 4 Data Constraint 对于50%的数据,M≤N≤1,000 。