分治算法
一、二分
二分本质是求边界
一定面对有序的,可以是大小,也可以是性质
你看这个二分查找
写好二分
首先你要有好模板
典型例题
1.借教室
打标记(差分维护前缀和)
O(1)打标记,O(n)求前缀和
O(m)是订单数
O(m+n)求出每天需要多少教室
2.
解析
在数字1~num中,
u表示能被x整除的数的个数
v表示能被y整除的数的个数
w 表示能被x*y整除的数的个数
因为在[1, num]里面,只有x,2x,3x,4x...
这么几个数能被 x 整除,而且对于 kx,需要保证 kx <= num
所以显然 k = floor(num / x)
二、三分
复杂度:log3/2N
如何比较两个实数的大小呢?? 如果我们有两个数字 a,b 经过一系列玄学操作 a,b在计算的时候精度可能会丢失 此时做差判断他们到底谁大 double eps=1e-8; fabs(a-b)<eps return 0; //表示a=b return a-b<0?-1:1;
那如果函数不是单峰怎么办?
三、分块
1.给出一个长度为n的数列,以及m个操作,支持区间加法,单点查询
(PS,为什么不用线段树??)
我们分块!!!
吧长为n的数组分成√n个块
给出询问区间 [ L , R ]
情况1:L,R在同一块里,暴力跑
情况2:L,R在相邻块里,暴力跑
情况3:L,R在不相邻块里,L~R之间每个块打标记
单点查询:自己加标记
2.给出一个长为n的数列以及m个操作,支持区间加法,并询问区间内小于等于某个数x的元素个数
长度为n的数列a,我们把它分块到b数组,√n一个块,然后每个块内部进行排序
(1) 给出询问区间 [ L , R ]
还是考虑三种情况
情况1:L,R在同一块里,暴力扫描 O(√n)
情况2:L,R在相邻块里,暴力扫描 O(2√n)
情况3:L,R在不相邻块里 O(√n log n)
(2) 区间加
L,R在一个块里就直接加啊,然后跑一遍快排 O(√n log n)
但是它的复杂度可以再低一点,达到
用均值不等式调整分块大小,查询复杂度和修改复杂度取均值不等式
3.给出一个长为n的数列以及m个操作,支持区间开放,区间求和
一个longlong 最多开方6次变1
扫描区间,若是01的一段区间,就标记,以后开方不用动了,因为不会改变了呀
假设你有一堆弹珠
红黄蓝绿红绿蓝紫粉黄粉蓝
color[i]:下标为i的球的颜色
pre[i]:前一个颜色为color[i]的球的下标编号
引理:
如果 pre[i]<x<i,那么在区间[x,i]之间有一个颜色为color[i]的球
so,
查询区间[l,r]里有多少不同颜色,等价于
查询区间[l,r]之间pre[i]<l的i的个数
也就是求[l,r]里有多少个pre[i]<l
这个可以用上面讲的2做
O(n)暴力修改能过
题外话
推荐oj
1.CF(cross fire(不是)) CodeForce
2.CodeChef(对高中生还算友好)
3.TopCoder
4.Div2