单调队列

POJ1821 Fence 单调队列优化DP

自闭症网瘾萝莉.ら 提交于 2019-11-28 13:27:18
http://poj.org/problem?id=1821 题意:给长度为n的木板,k个工人,每个工人要么不粉刷,或者选择一个包含木板si,长度不超过li的连续的一段木板粉刷,每粉刷一块得到pi的报酬,问如何安排工人使得总报酬最大? 思路:可以按si给工人排序,这样我们就可以按照顺序依次安排工人。设f[i][j]表示到第i个工人,刷到前j块木板的最大报酬, 三种情况 工人不刷:f[i][j]=f[i-1][j] 木板空着:f[i][j]=f[i][j-1] 第i个工人刷k+1到j的木板,其中k,j满足k+1<=si<=j,报酬就是f[i][j]=f[i-1][k]+pi*(j-k),拆开得pi*j+(-pi*k+f[i-1][k])。可以发现对于每个j来说,要找到它对应的最大报酬,需要尝试范围内的所有k值,而实际上我们可以发现随着枚举j,j的增大,所对应的k的区间范围的上下界也是递增的,这样的话,我们就可以考虑使用单调队列来优化枚举k的过程,又因为要使报酬最大,所以我们需要维护一个单调递减的序列来维护-pi*k+f[i-1][k]这个只与k相关的最大值。 #include<cstdio> #include<algorithm> using namespace std; const int maxn=16005; struct note { int l,p,s; } a[maxn]

洛谷P1638逛画展【单调队列】

天大地大妈咪最大 提交于 2019-11-28 09:46:37
1.逛画展 洛谷P1638 题目描述 博览馆正在展出由世上最佳的 M 位画家所画的图画。 wangjy想到博览馆去看这几位大师的作品。 可是,那里的博览馆有一个很奇怪的规定,就是在购买门票时必须说明两个数字, a和b,代表他要看展览中的第 a 幅至第 b 幅画(包含 a 和 b)之间的所有图画,而门票 的价钱就是一张图画一元。 为了看到更多名师的画,wangjy希望入场后可以看到所有名师的图画(至少各一张)。 可是他又想节省金钱。。。 作为wangjy的朋友,他请你写一个程序决定他购买门票时的 a 值和 b 值。 输入格式 第一行是 N 和 M,分别代表博览馆内的图画总数及这些图画是由多少位名师的画 所绘画的。 其后的一行包含 N 个数字,它们都介于 1 和 M 之间,代表该位名师的编号。 输出格式 a和 b(a<=b) 由一个空格符所隔开。 保证有解,如果多解,输出a最小的。 输入输出样例 输入 #1 复制 12 5 2 5 3 1 3 2 4 1 1 5 4 3 输出 #1 复制 2 7 说明/提示 约定 30%的数据N<=200 , M<=20 60%的数据N<=10000 , M<=1000 100%的数据N<=1000000 , M<=2000 #include<stdio.h> int m[2001],num; int n[1000000]; int main() {

【模板】 单调队列

本小妞迷上赌 提交于 2019-11-28 04:15:38
1 #include<bits/stdc++.h> 2 using namespace std; 3 int a[1000+5][1000+5]; 4 int X[1000+5][1000+5]; 5 int x[1000+5][1000+5]; 6 int Y[1000+5][1000+5]; 7 int y[1000+5][1000+5]; 8 int Q[1000+5]; 9 int q[1000+5]; 10 int main(){ 11 int n,m,k;scanf("%d%d%d",&n,&m,&k); 12 for(int i=1;i<=n;++i){ 13 for(int j=1;j<=m;++j) 14 scanf("%d",&a[i][j]); 15 } 16 int F,B,f,b; 17 for(int i=1;i<=n;++i){ 18 F=B=f=b=Q[1]=q[1]=1; 19 for(int j=2;j<=m;++j){ 20 while(a[i][j]>=a[i][Q[B]]&&F<=B) --B; 21 while(a[i][j]<=a[i][q[b]]&&f<=b) --b; 22 Q[++B]=q[++b]=j; 23 while(j-Q[F]>=k) ++F; 24 while(j-q[f]>=k) ++f; 25 if(j>=k){

【单调队列】

我的未来我决定 提交于 2019-11-28 04:12:10
单调队列优化 做动态规划时常常会见到形如这样的转移方程: \(f[i] = optimize\{g(j)|L[i] ≤ j < i \rbrace+w[i]\) 其中 \(L[1] ≤ L[2] ≤ · · · ≤ L[n]\) ( \(g[j]\) 表示一个和j或 \(f[j]\) 有关的函数, \(w[i]\) 表示一个和i有关的函数) 有这样一个性质:如果存在两个数 \(j,k\) ,使得 \(k ≤ j\) ,而且 \(g(k) ≤ g(j) (opt = max)\) 或 \(g(j) ≤ g(k)(opt = min)\) ,则决策k 是毫无用处的。 根据 \(L[i]\) 单调的特性,如果 k 可以作为合法决策,那么 j一定可以作为合法决策,又因为 j 比 k 要优 (注意: 在这个经典模型中,“优”是绝对的,与当前正在计算的状态⽆关),因此如果把表中的决策按照 j 排序的话,则 \(g(j)\) 必然不升 \((opt=max)\) 或必然不降 \((opt=min)\) 。 1、 计算 \(g(x)\) ,并将其插入到单调队列的尾部,同时维持队列的单调性(不断地出队,直到队列单调为止)。 2、 队首元素出队,直到队首元素在给定的范围中。 3、 此时,队首元素就是状态f(x)的最优决策, 重复上述步骤直到所有的函数值均被计算出来。不难看出这样的算法均摊时间复杂度是

单调队列——小游戏

半世苍凉 提交于 2019-11-28 04:04:38
·今天考试题!!然鹅爆了!! · 题目内容 : 1 .Background CZR 虽然已经是个大学生了,但是他还是喜欢在家里偷偷玩跳格子 . 2. Description CZR 的家里有连续的 N + 1 块地砖,编号为 0 到 N ,他在每一块地砖上 都写上了一个数字 . 一开始他在 0 号地砖,这块地砖的分数为 0 ,每次他都会后面跳一步, 但是他不一定需要跳到最后 . 因为他跳远能力不行,所以他一步只能往后跳 L 到 R 个格子,也就是说 在地砖 i 时,他只能跳到地砖 i + L 到 i + R 中的一块地砖 . 他进行一次游戏的分数总和是他跳到的所有地砖的分数之和 . 他现在想获得最大的分数,来证明自己的数学能力很强,所以他需要 知道最大分数是多少 . · 题目来源 :山东济南集训考试题二第二题 · 题目思路 : 令F[i]表示CZR跳到格子i上的时候,他能获得的最大分数. 则F[i] = max(F[i – L]…F[i - R]) + a[i].(a[i]表示i点的分数) 我们想要优化这个max(F[i – L]…F[i - R]). 这个i是取遍1-n的. 简单的来说就是要求一个区间最大值,区间长度是固定的. 有很多方法可以来做: 一个最简单的方法就是单调队列. 求区间最大值,区间固定,这显然是简单的单调队列的优化题. 而且单调队列也很好写

单调栈&单调队列

旧巷老猫 提交于 2019-11-28 00:51:45
单调栈 定义 : 单调栈是指一个栈内部的元素是具有严格单调性的一种数据结构,分为单调递增栈和单调递减栈。 性质: ① 满足从栈顶到栈底元素具有严格的单调性。 ② 满足栈的后进先出特性,越靠近栈底的元素越早进栈。 单调队列 定义: 单调队列是指一个队列内部的元素具有严格单调性的一种数据结构,分为单调递增队列和单调递减队列。 性质: ① 单调队列必须满足从队头到队尾的严格单调性。 ② 满足队列的先进先出特性,排在队列前面的比排在队列后面的要先出队。 练习 单调栈和单调队列可以用STL中的stack(栈)和deque(双端队列)实现,也可以手写数组实现并且因为数据只会进出至多一次,所以不会超限。 单调栈&单调队列的思想和实现都比较简单,可以试做以下例题去体验这种思想。 单调栈: poj 3250 Bad Hair Day #include<iostream> #include<cstdio> #include<stack> using namespace std; int const maxn=80005; long long h[maxn],sum; stack<long long> sta; int main() { int n,i; scanf("%d",&n); for(i=1;i<=n;i++) scanf("%lld",&h[i]); for(i=1;i<=n;i++) {

单调队列&&单调栈

£可爱£侵袭症+ 提交于 2019-11-28 00:18:05
https://www.cnblogs.com/tham/p/8038828.html(参考文章) 单调队列 Poj 2823 给定一个数列,从左至右输出每个长度为m的数列段内的最小数和最大数。 数列长度: N <= 10 6 , m <= N 直接暴力求解复杂度在0(mn) 可以考虑维护区间最值,单调队列则是维护区间队列的强大武器 单调队列的定义: 1、维护区间最值 2、去除冗杂状态 如上题,区间中的两个元素a[i],a[j](假设现在再求最大值) 若 j>i且a[j]>=a[i] ,a[j]比a[i]还大而且还在后面(目前a[j]留在队列肯定比a[i]有用,因为你是往后推, 核心思想 !!!) 3、保持队列单调,最大值是单调递减序列,最小值反之 4、最优选择在队列 单调队列实现的大致过程: 1、维护队首(对于上题就是如果队首已经是当前元素的m个之前,则队首就应该被删了,head++) 2、在队尾插入(每插入一个就要从队尾开始往前去除冗杂状态,保持单调性) 简单举例应用 数列为:6 4 10 10 8 6 4 2 12 14 N=10,K=3; 那么我们构造一个长度为3的单调递减队列: 首先,那6和它的位置0放入队列中,我们用(6,0)表示,每一步插入元素时队列中的元素如下 插入6:(6,0); 插入4:(6,0),(4,1); 插入10:(10,2); 插入第二个10

【单调队列】--滑动窗口

我的未来我决定 提交于 2019-11-27 21:54:34
题目链接 给定一个大小为 n ≤ 10 6 n≤106的数组。 有一个大小为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 您的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。 输入格式 输入包含两行。 第一行包含两个整数n和k,分别代表数组长度和滑动窗口的长度。 第二行有n个整数,代表数组的具体数值。 同行数据之间用空格隔开。 输出格式 输出包含两个。 第一行输出,从左至右,每个位置滑动窗口中的最小值。 第二行输出,从左至右,每个位置滑动窗口中的最大值。 输入样例: 8 3 1 3 -1 -3 5 3 6 7 输出样例: -1 -3 -3 -3 3 3 3 3 5 5 6 7思路:首先想暴力的做法,时间复杂度是O(n*k),然后再来看是否可以优化的地方。以输窗口最小值为例:可以发现,在一个窗口中,如果来了一个小的数

单调队列总结

余生长醉 提交于 2019-11-27 20:43:22
最近做了许多单调队列的题,也有了一些感悟 单调队列的题都可以用下面的代码来套 1 for(i = 1;i <= n; ++i) { 2 while(lst < L) ++lst;//or other 3 for(;lst < i; ++lst) { 4 while(hd <= tl && __ _ __) --tl; 5 q[++tl] = lst; 6 } 7 while(hd <= tl && q[hd] < L) ++hd; 8 __ = _q[hd]_; 9 } $hd$为队头,$tl$为队尾(左闭右闭),$lst$为还未插入的决策点的最左端的位置,其中代码并不是固定的,具体情况具体分析 来源: https://www.cnblogs.com/mzg1805/p/11375714.html

单调队列优化DP

蹲街弑〆低调 提交于 2019-11-27 18:11:07
做了几道前几天多校的单调队列优化DP题目: hdu 4326 Dragon Ball http://acm.hdu.edu.cn/showproblem.php?pid=4362 题意: Sean的到一个地图上边标有什么时刻什么地点会出现龙珠,龙珠在每一时刻出现在同一行里,Sean每一时刻只能去一个龙珠,给出他取龙珠所消耗的能量以及移动所消耗的能量。求他在每个时间段取龙珠的最小能量消耗; 思路: dp[i][j]表示在i时间取第j个龙珠的最小能量消耗 则有dp[i][j] = min(dp[i - 1][k],abs(p[i - 1][k].pos - p[i][j].pos)) + p[i][j].w; 此方法复杂度为O(m*n^2)会超时 假设如果都是从当前点的左边来的则有: dp[i][j] = min(dp[i - 1][k] - p[i - 1][k].pos) + p[i][j].pos + p[i][j].w; 而对于dp[i - 1][k] - p[i - 1][k].pos为定值可以用单调队列维护,从右边来的同理; 这里我们主要是是在在对左边排序上的复杂度优化为O(m*nlogn) 话说奇了个怪了,昨天晚上写了很长时间就是不对,今天早上写完就A了。。无语了。。 View Code #include <iostream> #include <cstdio>