分治算法

分治算法

一、二分

二分本质是求边界

一定面对有序的,可以是大小,也可以是性质

你看这个二分查找

写好二分

首先你要有好模板

 

 典型例题

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

原文地址:https://www.cnblogs.com/xiaoyezi-wink/p/11184127.html