Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

基础算法

贪心

根据贪心的数学背景我们在做贪心题目的时候一般有两种策略: 1.把一个问题划分成很多子问题,对于每个子问题直接求最优解,然后合成一个最优解; 2.对于当前局面,搜索所有可能的“临近局面”,选择最优的局面进行转移

数据范围较大时,一般使用贪心

贪心的复杂度一般很小

eg1.

按单价排序即可

eg2.

9rw1gI.png(https://imgchr.com/i/9rw1gI.webp.webp.webp.webp.webp)

数学上的mod指如果mod为负数,不断加模数直到为正数.

即 '5 mod 6 = 5'

eg3-4

紫书区间问题

eg5.

非矩形贪心问题一定要转化成线段问题


  • 雷达放在x轴上一定比放在x轴下方更优

错误思路

从左到右考虑所有岛,在能探测到一个岛的前提下,尽可能的向右放

由于圆的特性,会出现以下反例

正确思路

考虑到圆的复杂,应转化为线段贪心问题.

改变研究对象

考虑研究每一个岛屿.

由于雷达的半径固定,所以对于每一个与x轴距离小于半径的岛屿,都能在x轴上找到一个区间,使这个区间里所有的雷达都能探测到这个岛屿.

问题转化为区间选点问题.

eg6.

进制问题

因为1!+2!+...+(n-1)! < n!

所以如果可以表示,则一定可以通过每次取最大的不超过n-已表示的数的数的阶乘得到

[一个我不知道为什么的结论]

eg7.

字典序最大即越靠前越大

当K<= N-1时,把第N个数换到最前

K>N-1时类似.

eg8.

过于复杂先挖个坑

贪心的骗分策略

1.贪心算法与随机化算法的结合(例如模拟退火)

  • 在决策时有概率接受比当前情况差的方向
  • 在搜索到结果时以一定概率跳出当前解,重新开始贪心
  • 在贪心开始的时候,利用随机化选择多个起点开始贪心,取其最小值
可以在最外层循环1000次随机起点来贪心,在数据范围小时极为有效

分治

分治的用处

分治算法在OI中的运用主要在两个方面:

  • 基于二分查找、三分查找的运用
  • 将题目划分为更细小的子问题的运用

二分

  • 本质:在一个范围里确定一个分界,使分界的左边满足一个条件,右边满足一个条件
  • 适用范围:范围满足单调性

常见使用情景:

  • 简单的二分查找
  • 在一个单调函数里寻找可行最值
  • 最值的最值

首先我们需要一个好的模板

while(l + 1 < r)
{
  int mid = (l + r + 1) >> 1;
  if(judge(mid))
  {
    r = mid;
  }else{
    l = mid;
  }
}
if(!judge(l))l = r;
//by Chtholly

eg1.

  • 借教室的原则是先到先得 这句话点明修改的订单编号满足单调性.即如果前面的订单都满足不了,后面的订单一定不能满足.如果后面的订单可以满足,前面的订单一定能满足.
  • 主题框架 既然满足单调性,不难想到二分.二分出能满足的订单与不能满足的订单的分界即可.
  • 数据结构 显然这道题多次进行区间修改,单点查询 的操作,考虑用差分来维护.

eg2.

有一个序列{Ai}以及m个区间[li..ri]
你现在可以选择k个区间,对于每个被选中的区间[l..r],Al~Ar的数都会增加delta
求在所有方案中a中最小值最大为多少
  • 二分 + 一些神奇的算法
  • 这个神奇的算法能计算出能否选中k个区间使任意一个点仍保持在k以下
  • 二分出k的最大值即可
  • 具体使什么神奇的算法我好像忘了但好像是贪心

eg3.

过于复杂先开个坑

三分

  • 使用范围:求一个单峰函数的最值

9rdXj0.png

ppt好像有错误不确定就不写了

归并类分治

分块!!!!!

类型

  • 给出一个长度为n的数列,以及m个操作,支持区间加法,单点查询
  • 给出一个长为n的数列以及m个操作,支持区间加法,并询问区间内小于等于某个数x的元素个数
  • 给出一个长为n的数列以及m个操作,支持区间开方,区间求和

分块

分块是线段树/树状数组的一个替代品.

给定一个区间,分为[sqrt(N)]块,每一块有[sqrt(N)]个元素.

剩余的不足[sqrt(N)]个元素单独暴力处理.

[]为向下取整

区间加法,单点查询

类lazy标记

每一块都有一个lazy标记.

加法区间内的整块加法,只需在加lazy标记上加.

查询时加上该块的标记即可.

不在整块内的?暴力啊啊啊啊!

区间加法,查询小于x的个数

每一块排序+二分 不解释

不在整块内的同样暴力啊啊啊

区间开方,区间求和

因为是向下取整开方,所以每一数在开方后多次后就会变为1

然后自己研究吧(狗屎)

eg1.

难点主要在如何求[l,r]之间不同的元素

用pre[i]代表上一次出现a[i]这个元素的位置,问题转化为查询[l,r]区间内pre[i] < l的个数.

O(n)即可完成预处理

2018-2-16

评论