https://flowus.cn/xjsc01/share/395ca9dc-315c-4bd5-a942-016709980c03
这里面有我个人内容的系统整理

队列和他的变种:

  • 普通队列
  • 双端队列
  • 优先队列(小根堆, 大跟堆)

习题AcWing132. 小组队列

我采用一个队列,表示小组的总的排行,然后使用小组个数个队列来保存每一个组里面的队列。
通过我这样一波操作,可以在队列的队列里面进行Push和Pop

代码

#include <bits/stdc++.h>
using namespace std;
int cnt = 1;
void Solve(int n)
{queue<int> total;bool inqueue[1005] = {false};vector<queue<int > >g(1005);//每一组的队列printf("Scenario #%d\n", cnt);map<int , int>mp;{for(int i = 1; i <= n; i++){int num;scanf("%d", &num);for(int j = 1; j <= num; j++){int buf;scanf("%d", &buf);mp[buf] = i;}}}char input[12];scanf("%s", input);while(input[0] != 'S'){int id;scanf("%d", &id);if(input[0] == 'E'){if(!inqueue[mp[id]]){inqueue[mp[id]] = true;total.push(mp[id]);}g[mp[id]].push(id);}else if(input[0] == 'D'){printf("%d\n", g[total.front()].front());g[total.front()].pop();if(g[total.front()].empty()){inqueue[total.front()] = false;total.pop();}}scanf("%s", input);}printf("\n");
}
int main()
{int n;while(scanf("%d", &n) && n) {Solve(n);cnt++;}return 0;
}

ACWing蚯蚓133

蛐蛐国最近蚯蚓成灾了!

隔壁跳蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手来帮他们消灭蚯蚓。

蛐蛐国里现在共有 n

只蚯蚓,第 i 只蚯蚓的长度为 a**i ,所有蚯蚓的长度都是非负整数,即可能存在长度为 0

的蚯蚓。

每一秒,神刀手会在所有的蚯蚓中,准确地找到最长的那一只,将其切成两段。

若有多只最长的,则任选一只。

神刀手切开蚯蚓的位置由有理数 p

决定。

一只长度为 x

的蚯蚓会被切成两只长度分别为 ⌊p**x⌋ 和 x−⌊p**x

的蚯蚓。

特殊地,如果这两个数的其中一个等于 0

,则这个长度为 0

的蚯蚓也会被保留。

此外,除了刚刚产生的两只新蚯蚓,其余蚯蚓的长度都会增加一个非负整数 q

蛐蛐国王知道这样不是长久之计,因为蚯蚓不仅会越来越多,还会越来越长。

蛐蛐国王决定求助于一位有着洪荒之力的神秘人物,但是救兵还需要 m

秒才能到来。

蛐蛐国王希望知道这 m

秒内的战况。

具体来说,他希望知道:

  1. m

秒内,每一秒被切断的蚯蚓被切断前的长度,共有 m

个数。

m

秒后,所有蚯蚓的长度,共有 n+m

  1. 个数。

输入格式

第一行包含六个整数 n,m,q,u,v,t

,其中:n,m,q 的意义参考题目描述;u,v,t 均为正整数;你需要自己计算 p=u/v(保证 0<u<v);t

是输出参数,其含义将会在输出格式中解释。

第二行包含 n

个非负整数,为 a1,a2,…,a**n,即初始时 n

只蚯蚓的长度。

同一行中相邻的两个数之间,恰好用一个空格隔开。

输出格式

第一行输出 ⌊m/t

个整数,按时间顺序,依次输出第 t 秒,第 2t 秒,第 3t

秒,……被切断蚯蚓(在被切断前)的长度。

第二行输出 ⌊(n+m)/t

个整数,输出 m 秒后蚯蚓的长度;需要按从大到小的顺序,依次输出排名第 t,第 2t,第 3t

,……的长度。

同一行中相邻的两个数之间,恰好用一个空格隔开。

即使某一行没有任何数需要输出,你也应输出一个空行。

请阅读样例来更好地理解这个格式。

数据范围

1≤n≤105

,
0≤a**i≤108,
0<p<1,
0≤q≤200,
0≤m≤7∗106,
0<u<v≤109,
1≤t≤71

输入样例:

3 7 1 1 3 1
3 3 2

输出样例:

3 4 4 4 5 5 6
6 6 6 5 5 4 4 3 2 2

样例解释

样例中,在神刀手到来前:3只蚯蚓的长度为 3,3,2。

1秒后:一只长度为 3 的蚯蚓被切成了两只长度分别为 1 和 2 的蚯蚓,其余蚯蚓的长度增加了 1。最终 4 只蚯蚓的长度分别为 (1,2),4,3。 括号表示这个位置刚刚有一只蚯蚓被切断。

2秒后:一只长度为 4 的蚯蚓被切成了 1 和 3。5 只蚯蚓的长度分别为:2,3,(1,3),4。

3 秒后:一只长度为 4 的蚯蚓被切断。6 只蚯蚓的长度分别为:3,4,2,4,(1,3)。

4秒后:一只长度为 4 的蚯蚓被切断。7 只蚯蚓的长度分别为:4,(1,3),3,5,2,4。

5秒后:一只长度为 5 的蚯蚓被切断。8 只蚯蚓的长度分别为:5,2,4,4,(1,4),3,5。

6秒后:一只长度为 5 的蚯蚓被切断。9 只蚯蚓的长度分别为:(1,4),3,5,5,2,5,4,6。

7秒后:一只长度为 6 的蚯蚓被切断。10 只蚯蚓的长度分别为:2,5,4,6,6,3,6,5,(2,4)。

所以,7秒内被切断的蚯蚓的长度依次为 3,4,4,4,5,5,6。

7秒后,所有蚯蚓长度从大到小排序为 6,6,6,5,5,4,4,3,2,2。

  1. 在这道题目,蚯蚓的长度是随着时间在进行着变化,可以知道,长度可以表达成y-t平面内的一个直线。斜率已知,使用每一只蚯蚓的初始长度来表达蚯蚓的长度(这样到最后输出时以及在比较过程中统一,好比较)。

  2. 这道题目可以使用优先队列来进行,但是时间复杂度是mlog2nmlog_2nmlog2​n 所以不太可能实现。

  3. 这时候就需要进行理性的思考,需要使用线性的时间来进行求解。

  4. 归纳总结一个问题:

    两类排序的比较:

    • 完全排一遍,然后找到规律,可以是线性。
    • 一直使用优先队列进行求解,时间复杂度是mlongn
    • 一直使用排序(不推荐)

这道题目中找规律:

注意:q>=0 ,并且0<p<1。

假设我第一遍已经把最初的排序排好了,然后从中取出一个最大的,然后切成两端,放回去。这样就没有利用到我最初排好的序。

PS:如果我发现把一个东西插入到线性的队列里面很复杂,那么就多开几个队列。

代码

    #include <bits/stdc++.h>using namespace std;typedef long long ll;queue<ll>que;queue<ll>que1;queue<ll>que2;ll buf[200006];ll n,m,q,u,v,di;ll t;//这个时间是动态变化的 void Divide(ll x, ll &t1, ll &t2){t1 = x * u / v;t2 = x - t1;}ll getnow(ll b, ll tt){return b + q * tt;}ll getb(ll now, ll tt){return now - tt * q;}void Process(ll x){x = getnow(x, t-1);ll t1 = x * u / v;ll t2 = x - t1;t1 = getb(t1, t);t2 = getb(t2, t);que1.push(t1);que2.push(t2);}int main(){scanf("%d%d%d%d%d%d", &n,&m,&q,&u,&v,&di);for(int i = 1; i <= n; i++){scanf("%lld", buf+i);}sort(buf+1, buf+1+n);for(int i = n; i >= 1; i--){que.push(buf[i]);}for(t = 1; t <= m; t++){ll out;ll tmp, tmp1, tmp2;tmp = tmp1 = tmp2 = -200000000;if(!que.empty()) tmp = que.front();if(!que1.empty()) tmp1 = que1.front();if(!que2.empty()) tmp2 = que2.front();if(tmp >= tmp1 && tmp >= tmp2)//tmp最大{out = tmp;Process(que.front());que.pop();}else if(tmp1 >= tmp && tmp1 >= tmp2)//tmp1最大{out = tmp1;Process(que1.front());que1.pop();}else //tmp2最大{out = tmp2;Process(que2.front());que2.pop();}if(t % di == 0){printf("%lld ", out + (t-1) * q);}}putchar('\n');for(int i = 1; i <= n+m; i++){ll out;ll tmp, tmp1, tmp2;tmp = tmp1 = tmp2 = -0x3f3f3f3f3f3f3f3f;if(que.size()) tmp = que.front();if(que1.size()) tmp1 = que1.front();if(que2.size()) tmp2 = que2.front();if(tmp >= tmp1 && tmp >= tmp2)//tmp最大{out = tmp;que.pop();}else if(tmp1 >= tmp && tmp1 >= tmp2)//tmp1最大{out = tmp1;que1.pop();}else //tmp2最大{out = tmp2;que2.pop();}if(i % di == 0)printf("%lld ", out + q * (t-1));}return 0;}

在这道题目中,一直都是段错误,细分析,是因为给负无穷大的时候给小了。

ACWing134. 双端队列

题面

达达现在碰到了一个棘手的问题,有 N个整数需要排序。

达达手头能用的工具就是若干个双端队列。她从 1到 N 需要依次处理这 N个数,对于每个数,达达能做以下两件事:

1.新建一个双端队列,并将当前数作为这个队列中的唯一的数;

2.将当前数放入已有的队列的头之前或者尾之后。

对所有的数处理完成之后,达达将这些队列按一定的顺序连接起来后就可以得到一个非降的序列。请你求出最少需要多少个双端序列。

输入格式

第一行输入整数 N,代表整数的个数。

接下来 N 行,每行包括一个整数 D**i,代表所需处理的整数。

输出格式

输出一个整数,代表最少需要的双端队列数。

数据范围

1≤N≤200000

输入样例:

6
3
6
0
9
6
3

输出样例:

2

题解

  1. 否定局部贪心:如果有p<q,且在一开始构成了一个队列,那么在之后,如果有一个数字位于p与q之间,那么就会没有解。

  2. 需要全局考虑。全局考虑先进行排序,然后就会有一些思路。

  3. 必须要把排序之后的进行分段,分成好几个小的区间,这样就可以满足 “达达将这些队列按一定的顺序连接起来后就可以得到一个非降的序列” 这一个条件。

  4. 现在还要考虑如何划分,才能满足“将当前数放入已有的队列的头之前或者尾之后或者新开一个队列”这样的条件。

  5. 由于排序,搞乱了现在与原来的关系,所以需要找到现在和原来输入顺序的关联(映射)。

  6. 上面的编号对应的是放进去的时间,在重新排序之后,成为红色部分。

  7. 对于每一段,都需要有一个最先放进去的(数字最小的),在它的两边,数字依次增加。

  8. 换句话说,就是找到一个具有单谷的段,并且极小值点的左边是单调递减,右边是单调递增。(该段内全部增加或者减少也可以,是特殊情况)

  9. 一定要注意:时间的排序(示意图最上面的哪一个是惟一的),but数值的大小是可以相同。所以有必要对于数值相同的进行一下交换,确保单谷的数目最多。

  10. 然后从左到右数出单谷区间的数目,这就是最终的答案。

不足总结

  1. 如果有两个变量,可以使用pair来代替结构体,因为pair更加简单并且sort函数可以直接对第一关键字进行排序。

错误代码

#include <bits/stdc++.h>
using namespace std;
#define N 20
//200005
typedef long long ll;
struct Node
{ll t;ll x;
}s[N];
bool bijiao(Node a, Node b)
{return a.x < b.x;
}
int main()
{int n;cin >> n;for(int i = 1; i <= n; i++) {cin >> s[i].x; s[i].t = i;}sort(s+1, s+1+n, bijiao);bool tag = false;//tag为1,表示上升,为0表示下降。ll last = LONG_LONG_MAX;//初始值为无穷大ll ans = 0;for(int p = 1; p <= n; ){int q = p;if((q+1) <= n && s[q+1].x == s[p].x) q++;ll maxx = s[p].t;ll minn = s[p].t;for(int j = p; j <= q; j++){maxx = max(maxx, s[j].t);minn = min(minn, s[j].t);}if(tag)//表示上升{if(minn < last){tag = false;last = minn;}else{last = maxx;}}else//表示下降{if(maxx > last){ans++;tag = true;last = maxx;}else{last = minn;}}p = q+1;}printf("%lld\n", ans);return 0;
}

错误之处:我的

  • 计数方法
  • maxx > last取不取等于号

与答案存在着矛盾。

如果输入

1
1 1

那么我的程序会输出0,显然错误!

我开始的时候数数的是凹下去的点的个数,但是因为最左边还有最右边的可能会缺少一半,所以不科学

eg:这个应该是有两个,但是我的程序会统计为一个。

数极大值的个数加上一就是答案,因为中间不可能缺少一半!

正确代码

#include <bits/stdc++.h>
using namespace std;
#define N 200005
typedef long long ll;
struct Node
{ll t;ll x;
}s[N];
bool bijiao(Node a, Node b)
{return a.x < b.x;
}
int main()
{int n;cin >> n;for(int i = 1; i <= n; i++) {cin >> s[i].x; s[i].t = i;}sort(s+1, s+1+n, bijiao);bool tag = false;//tag为1,表示上升,为0表示下降。ll last = LONG_LONG_MAX;//初始值为无穷大ll ans = 1;for(int p = 1; p <= n; ){int q = p;while((q+1) <= n && s[q+1].x == s[p].x) q++;ll maxx = s[p].t;ll minn = s[p].t;for(int j = p; j <= q; j++){maxx = max(maxx, s[j].t);minn = min(minn, s[j].t);}if(tag)//表示上升{if(minn < last){tag = false;last = minn;ans++;}else{last = maxx;}}else//表示下降{if(maxx > last){tag = true;last = maxx;}else{last = minn;}}p = q+1;}printf("%lld\n", ans);return 0;
}

ACWing135. 最大子序和

题面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k2ONQYIP-1656242960981)(队列.assets/image-20220626180600264.png)]

题解

对于一个区间的操作,可以使用前缀和来进行想象。

如果使用最暴力的方法来进行求解,便是枚举左右端点,显然不行。

**注意:**虽然枚举两遍是不可以的,但是枚举一遍还是可行的。

**注意:**对于前缀和的枚举,可以转化为滑动窗口。

理论推理:
考虑枚举右端点,此时,需要让右端点到左端点的S长度内找到一个最小的值。

对于单调队列,可以

  1. 快速找到端点(最优解)
  2. 借助单调性来进行排除。

单调队列的特点:

  • 是单调的
  • 一端可以插入,也可以删除
  • 另一端可以删除(随着时间的推移,之前的元素会被删除!)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 300006
ll s[N];
deque<pair<ll,ll> > dq;
int n, m;
int main()
{ll ans = LONG_LONG_MIN;cin >> n >> m;for(int i = 1; i <= n; i++) scanf("%lld", s+i);for(int i = 1; i <= n; i++) s[i] += s[i-1];//s数组里现在已经是前缀和//dq.push_back(make_pair(0LL, 0));for(ll i = 1; i <= n; i++){while(dq.size() && dq.front().first < (i-m)) dq.pop_front();while(dq.size() && dq.back().second >= s[i-1]) dq.pop_back();dq.push_back(make_pair(i-1, s[i-1]));ans = max(ans,s[i] - dq.front().second);//if(i==6)调试专用代码!!!//{//    while(dq.size())//    {//        printf("%d ", dq.front());//        dq.pop_front();//        //    }//    exit(0);//}}cout << ans;return 0;
}

算法竞赛进阶指南——队列学习笔记相关推荐

  1. 【读书笔记】《算法竞赛进阶指南》读书笔记——0x00基本算法

    to-do: 例题: POJ 1845 Sumdiv 所有的课后习题: 随缘~~~ 位运算 对于一个二进制数,通常称其最低位为第0位,从右往左依此类推. 补码 unsigned int 直接将其看作3 ...

  2. 【读书笔记】《算法竞赛进阶指南》读书笔记——0x10基本数据结构

    to do(perhaps never) CH1401 后缀数组 所有课后题 栈 例题:HDU4699 Editor 维护一个整数序列的编辑器,支持以下五种操作: I x:在当前光标位置处插入一个整数 ...

  3. 中位数--《算法竞赛进阶指南》(货仓选址和七夕祭问题详解)

    中位数 今天又和大家见面了啦~ 依旧是 <算法竞赛进阶指南>的学习哦~ 中位数(Median)又称中值,统计学中的专有名词,是按顺序排列的一组数据中居于中间位置的数,代表一个样本.种群或概 ...

  4. 金字塔(算法竞赛进阶指南)

    虽然探索金字塔是极其老套的剧情,但是有一队探险家还是到了某金字塔脚下. 经过多年的研究,科学家对这座金字塔的内部结构已经有所了解. 首先,金字塔由若干房间组成,房间之间连有通道. 如果把房间看作节点, ...

  5. 算法竞赛进阶指南 萌新入门!

    算法竞赛进阶指南 文章目录 算法竞赛进阶指南 前言 一.介绍本书 二.如何阅读本书 三.总结 **笔记思路和结构 ** 算法竞赛进阶指南 这篇文章就简单的写一下吧! 前言 ​ 作为一个想要入坑的算法的 ...

  6. 《算法竞赛进阶指南》打卡-基本算法-AcWing 93. 递归实现组合型枚举:递归与递推、dfs、状态压缩

    文章目录 题目解答 题目链接 题目解答 分析: 此题和笔者另一篇博文很像,只不过是限定了个数.<算法竞赛进阶指南>打卡-基本算法-AcWing 92. 递归实现指数型枚举:递推与递归.二进 ...

  7. 《算法竞赛进阶指南》数论篇

    <算法竞赛进阶指南>数论篇(1)-最大公约数,素数筛,欧拉函数,同余,欧拉定理,BSGS <算法竞赛进阶指南>数论篇(1)-最大公约数,素数筛,欧拉函数,同余,欧拉定理,BSG ...

  8. 《算法竞赛进阶指南(by 李煜东)》习题题解 集合

    又是笔者给自己挖的大坑. 这里是李煜东所著<算法竞赛进阶指南(by 李煜东)>的习题题解集合. 有任何错误请在对应文章下反馈或联系 nicest1919@163.com ,谢谢 qwq 从 ...

  9. CH5202 自然数拆分Lunatic版(算法竞赛进阶指南,完全背包)

    算法竞赛进阶指南,278页,完全背包 本题要点: 1.把完全背包的代码改改即可.常规的完全背包: 有n个物品,每个物品的体积是v[i], 价值是w[i], 求装到大小为m的大背包,能获得的最大价值(每 ...

最新文章

  1. java面向对象思维导图_2020年Java进阶架构师的必备思维导图,让你少走弯路!
  2. 在Objective C中定义私有的成员变量
  3. 【MongoDB】嵌套数组查询方案
  4. 轻量级消息队列RedisQueue
  5. fastreport 打印两个list_Smaller And Smarter Python数据结构:合并两个有序链表
  6. [转]序列化悍将Protobuf-Net,入门动手实录
  7. android横向滑动控件,Android学习——HorizontalScollview水平滚动控件
  8. python有参装饰器详解_Python 带有参数的装饰器实例代码详解
  9. jquery ajax自动生成表格table(一)
  10. EDA技术实用教程 | 复习一 | IP核的概念和分类
  11. Windows API函数大全(Windows编程参考手册)
  12. 用计算机数字技术制作的电影是,计算机数字技术为电影带来的空前发展.doc
  13. 实践致知第7享:Windows如何设置文件的默认打开方式?
  14. 全缓存、行缓存和无缓存
  15. sqli-labs简单安装
  16. 《第一行代码》 第一章:第一行Android代码
  17. 双系统启动项设置为上次所选系统
  18. php1050r210,parker电磁阀parker柱塞泵parker马达
  19. frontpage动态html效果,FrontPage基础教程特效按钮的制作
  20. phoenix 安装教程

热门文章

  1. 计算机设备问题代码43,设备管理器错误代码(代码43)的六种解决方法
  2. 李书福造手机,会走上周鸿祎和董明珠的老路吗?
  3. 佛说:人就是苦今生修来生
  4. edit类型 layui_Layer types described(图层类型描述)
  5. 小软件大用途!分享4款超级实用的软件,请低调收藏
  6. 华为HCIP题库和考试相关注意事项
  7. 【转】Linux 里有/lib和/usr/lib,这两个目录下的库文件有什么区别吗?如果没区别为什么又要分开放呢
  8. 计算机二级c语言选择题及答案,全国计算机二级c语言练习题及答案
  9. 误删WinSock和WinSock2导致无法上网解决办法
  10. tp框架创建新文件夹