- 排序
(1)基数排序
从最小的优先级开始排序即可。有些题?可能会用
具体方法是第一遍开一堆桶统计某一关键字的数的数量,确定每个关键字在排序后位置从哪里开始。第二遍扫描直接放入相应位置即可。
(有点鸡肋不过还是可以了解)
基数排序2需要使用离谱到爆的位运算和卡常。
(2)快速排序
Sort
手写:每一次找一个中轴数,把比他大的移到右边,比他小的移到左边(用两个指针分别从左边和右边开始往中间扫,两边都找到符合条件的就交换),然后两边递归下去。
(3)归并排序
归并排序时可以顺便统计。先以二分方式递归,合并两个有序区间的时候利用走指针的方式用O(n)即可合并,对于左边区间的数a[i],如果它比右边区间的某一个数a[j]大,就会产生mid-i+1个逆序对(a[j]比左边区间大于a[i]的所有数都要小)
- 离散化。经常会用到。
(1)安排任务。离散化后直接dp即可
- 堆
(1)维护时序最值
①合并果子
②无穷序列2.都是用堆来优化贪心之类
(2)懒删除
①就是删除堆里面的东西。用struct 维护一个堆中元素编号,然后开一个数组记录是否删掉就行。
②priority_queue的重载。可以在struct里面重载小于号或者再开一个结构体重载括号
这样便可以从大到小按v排序了
(1)优化贪心和动态规划问题
- 中位数:
考虑把一个序列分为大的一半和小的一半。
每一次的答案即为大的那一半的最小值和小的那一半的最大值中取出。
显然两半数量的差值最多为1.如果有一半多直接输出那一半的最值,反之输出两个最值的平均数。
考虑每次插入的时候对某一半的最值进行比较后插入某一边,之后如果两半数量差大于1就要把多的元素拿一个给少的那一半。
用堆实现两半最值。
- 堆1:
堆的模板题。
- 堆2:
?堆的STL?模版?
- 无穷序列1/2
考虑每一次选择最小y时,总会从每一个函数的可选择的最小x中选择最小的f(x)。
因此只需要维护每一个函数的可以选择的最小值即可
开一个结构体priority_queue即可
- 逆序对
归并排序
归并排序时可以顺便统计。先以二分方式递归,合并两个有序区间的时候利用走指针的方式用O(n)即可合并,对于左边区间的数a[i],如果它比右边区间的某一个数a[j]大,就会产生mid-i+1个逆序对(a[j]比左边区间大于a[i]的所有数都要小)
树状数组
直接暴力统计,按照时间顺序把每个元素加入树状数组中,加入后统计比这个数大的数的个数即可。在数字太大时需要进行离散化。
- 方格背包问题
考虑动态规划
设f[i][j][k]表示走到(i,j)时格子数的和%p=k时的方案数
转移很简单从左边和上面转移过来就可以了,方案数加起来mod
但是可能用ijk更新右边和下面会好写一点。
初始化就是f[1][1][a[1][1]]=1
然后你突然发现空间不够(离谱)
很简单的问题可以用0\1压掉i
- 开船
考虑堆
需要进行堆内编号和实际编号的互相映射(离谱),其他就是裸堆。
具体操作方法:在加入的时候直接加入堆中并给它一个堆中编号,用堆中编号和实际编号进行互相映射。在扔人的时候首先算出哪个人要被扔走,找到实际编号为它的人,把这个人的对应堆内编号标记为被删除(懒删除),然后把最后一个人的堆内编号和已删除人的实际编号进行相互映射并改变其幸运值。最后把实际人数减一(实际操作有点烦)
- 开车
考虑每次全部加满,消耗时优先消耗价格最低的油,到了一个新的地方把贵的油退掉换成新的。最后把没用完的油也退掉。应该算是一个贪心,不过需要用到堆优化。
这个题启发我们不要光从模拟角度去思考问题,否则很多题目都想不到答案(这题在哪)
- 单调区间最大值
堆的作用:时序集合最值。对询问按右端点排序即可。
- 字符串排序
第一个问题:使用sort(离谱)
第二个问题:给结构体排序就行了,标记一下那些需要输出的字符串
STRING可以通过>等比较字典序大小(牛逼嗷)
第三个问题:若要查询aaa则在原来的字符串集合中加入aaa和aab排序后在它们中间的字符串的数量就是答案。
实现细节自己考虑