首页 > 其他分享 >根号分治

根号分治

时间:2024-01-22 13:00:14浏览次数:21  
标签:le 分治 路径 sqrt 答案 长度 根号

原本准备讲题用的,结果讲急了没用上。

乱写的,就扔这儿吧。


先看一个题。

CF797E Array Queries

  • 给定长度为 \(n\) 的序列 \(a\)。\(m\) 次询问。
  • 每次询问给出 \(p,k\)。您要不断地执行操作 \(p\gets p+a_p+k\),直到 \(p>n\) 为止。询问的答案为操作次数。
  • \(1\le n,q\le 10^5\),\(1\le a_i\le n\),\(1\le p,k\le n\)。

首先考虑每次询问直接做会发生什么。

如果 \(k\) 都很小的时候显然直接做是会撑到接近 \(O(n)\) 去世的。但是如果比较大的话,操作次数较少,倒还能撑。

那预处理一些信息呢?

一次 \(O(n)\) DP 可以求出 \(k\) 为一个定值的时候所有 \(p\) 的答案。但是 \(k\) 上限很大的时候显然不能做 \(k\) 次把所有情况都找出来。

于是 \(k\) 小的时候预处理是可行的,\(k\) 大的时候直接暴力跑是可行的。到底用哪个能多拿一点分呢。

小孩子才做选择,我全都要!

不如直接选定一个分割点 \(B\),\(k\le B\) 的时候使用预处理出来的结果直接输出,预处理复杂度 \(O(nB)\),\(k>B\) 的时候直接暴力跑一遍,最坏复杂度 \(O(q\frac{n}{B})\)。总复杂度 \(O(nB+q\frac{n}{B})\)。

最后只剩 \(B\) 应该选多少的问题了。显然如果要让两种做法的效率较为均衡的话,选 \(\sqrt{n}\) 是最优的。

于是喜提一个约为 \(O(n\sqrt{n})\) 的能过做法!


根号分治

顾名思义,对于一个数据范围为 \(n\) 的问题,如果在规模为 \(x\) 的情况下,你可以找出 \(O(x)\) 和 \(O(\frac{n}{x})\) (或带一点 \(\log\) 之类的抽象东西)的两种做法,但单独使用其中一种无法直接通过此题,这时你就可以考虑把它们组合起来,对于 \(x\) 的大小选择跑得更快的那一个方法。通常分割点选在 \(\sqrt{n}\),这样大概就可以稳定到一个 \(O(n\sqrt{n})\) 的级别。

对于其中某些问题可以片面地理解为把离线算法和在线算法混合起来

大概当注意到题目里有“两个与时间复杂度相关的元素的值的乘积不大于某个值”之类的性质,就可以往根号分治考虑了。

思想很简单,但是每个题的具体实现都不一样,比较灵活,还是有点考验思维的。值得注意的是因为复杂度带个根号,通常这种题目时限都是卡满的,建议写的时候有意识地选择常数更小的写法

看点没那么裸的题。


Topcoder SRM589 Level-3 FlippingBits

  • 给定 \(n,m\) 和一个长度为 \(n\) 的 01 字符串。
  • 你可以进行若干次操作。
  • 每次操作可以将字符串里的一个位置取反,或者是将一段长度为 \(m\) 的倍数的前缀全部取反。
  • 问最少需要多少次操作,才能使字符串的循环节为 \(m\)。
  • 循环节长度为 \(m\) 定义为,对于任意 \(i\),如果 \(i+m\) 这个位置存在,那么两个位置上的字符相等。
  • \(n \le 100\)。

感觉挺 \(O(n^3)\),但不像直接 DP 能搞的东西。

发现循环节个数和循环节长度的乘积并不超过 \(n\)。根号分治,启动!

若 \(m\le \sqrt{n}\),即循环节个数不超过 \(17\),那么也只有 \(17\) 种前缀取反方式,枚举哪几种被用了(显然用两次和不用没有区别),然后跑一遍整个字符串看还要几次单独取反,次数加起来取最小值即可。

若 \(m>\sqrt{n}\),则循环节长度不超过 \(17\),则你可以直接枚举这个循环节长什么样,然后用最优方式构造出一种操作方法使得次数最小,也就是使后面的循环节等于目前枚举的循环节或者其反串。这个理论上可以 DP 每段循环节是枚举的原串还是反串解决,每次从原串变成反串或者反串变原串都将次数加一(多一次前缀取反)。

所以实际复杂度 \(O(n2^{\sqrt{n}})\)。

不知道什么题

  • 给定一个 \(n\) 个点 \(m\) 条边的无向图,初始每个点都是黑色或白色。
  • 有两种操作:
    • 将一个点反色。
    • 查询与某个点直接连边的点中有多少个黑点。
  • \(n,m,q \le 10^5\)。

首先如果出边少的话暴力维护其它点的答案显然是可以直接过的。

但是出边多咋办呢?

这时需要想到,边数固定,那么既然出边数量都到了会让你爆炸的程度,这样的点还能有多少个呢?

所以这时不如以 \(B=\sqrt{m}\) 为界,出边小于 \(B\) 的点直接修改连向的点的答案,出边大于 \(B\) 就记有多少其他的点连向了这个点,然后仅记录这些点被翻的次数,查询其它小点时看有没有连到这样被翻过的大点。\(O(m\sqrt{m})\)。

所以根号分治有时候分的不只是数据范围,还可以是其它抽象的东西。

CF1039D You Are Given a Tree

  • 有一棵 \(n\) 个节点的树。
  • 其中一个简单路径的集合被称为 \(k\) 合法当且仅当:树的每个节点至多属于其中一条路径,且每条路径恰好包含 \(k\) 个点。
  • 对于 \(k\in [1,n]\),求出 \(k\) 合法路径集合的最多路径。即:设 \(k\) 合法路径集合为 \(S\),求最大的 \(|S|\)。
  • \(n \leq 10^5\)。7s。

首先考虑如果 \(k\) 是定值,能不能快速求出答案。一眼感觉挺像树形 DP,实际上不完全是。

假设现在位于 \(p\) 点,则路径的选取有两种可能:选一个儿子接到 \(p\) 上形成一条长度加 \(1\) 的链,继续往上接;选两个儿子和 \(p\) 接起来形成一条长度为两个儿子下面接的链的长度加上 \(1\) 的链,上面重新开一条新链。

如果是第一种情况的话显然取子树里那条最长的链往上连是最优的,更容易出现长度足够的路径。

考虑什么时候用第二种情况。设它的儿子所在的最长、次长链分别为 \(a,b\)。首先直接取 \(a,b\) 来配是最容易出现长度达到 \(k\) 的新路径的。然后猜有这么个结论:如果 \(a,b\) 配起来长度达到 \(k\),那么先把 \(a,b\) 放到一起配成新路径是肯定不会比单独取 \(a\) 往上连的结果要劣的。当然如果配不上就不得不选第一种情况了。

发现大概是可以证明的。设最长、次长链分别为 \(a,b\)。如果把 \(a\) 继续往上连也找不到长度达到 \(k\) 的方式,那么你显然亏了。如果 \(a\) 往上连,它自身长度达到了 \(k\) 或是与另一条链组合达到了 \(k\),即存在一种让这条链达到 \(k\) 的方式,那么如果你在这里把 \(a,b\) 连起来,重开一条链往上走,还是有可能存在另一种使这条链长度达到 \(k\) 的方式,这样你依然亏了。当然也可能确实重开之后就没有办法达到 \(k\) 了,不幸损失一条路径,但是同时下面 \(a,b\) 又连成了一条新路径,这样也仅仅是不亏不赚而已,没有什么影响。

不咋严谨,感性理解。

于是我们获得了一个 \(O(n^2)\) 的过不了做法。

发现 \(k\) 与答案的乘积不会超过 \(n\),启动根号分治。

当 \(k\le \sqrt{n}\) 的时候,直接按上面方法贪心预处理求出每一个点在每一个 \(k\) 下的答案即可。

当 \(k>\sqrt{n}\) 的时候,答案不会超过 \(\sqrt{n}\)。考虑反过来枚举答案,求有哪些 \(k\) 是这个答案。意识到答案随 \(k\) 的增大而减小,于是答案相等的 \(k\) 一定在一段区间内,二分跑 \(\log n\) 次树形 DP 求出每个答案第一次被取到的 \(k\) 即可。

于是我们获得了一个 \(O(n\sqrt{n}\log n)\) 的理论能过做法。

然而实践发现被卡常了,所以有几个小优化:

  • 可以把 dfs 序和每个点的祖先预处理出来再按顺序跑,除掉递归的常数。到这里 6s。
  • 每次二分的时候并不需要对整个 \([1,n]\) 都找一遍。如果从小到大枚举答案的话,你已经确定了前面答案所在的区间,位于整个 \([1,N]\) 的尾部,那把二分右端点放在上一个答案的前一位跑就够了。到这里 3s。
  • 注意到按 \(\sqrt{n}\) 分割的话两部分做法时间复杂度并不统一,理论上取 \(\sqrt{n\log n}\) 才是最优的。到这里 2s。

标签:le,分治,路径,sqrt,答案,长度,根号
From: https://www.cnblogs.com/CarroT1212/p/17979831/Divide-By-Sqrt

相关文章

  • 一本通金牌导航 分治法 E.工程划分 / P5290 [十二省联考 2019] 春节十二响(启发式合并)
    题目传送门题意简述:将树上\(n\)个点划分为若干个集合,使得集合中的点两两没有祖孙关系。一个集合的权值是集合内点的权值的最大值,求所有集合的权值之和的最小值。首先这题有个非常显然的贪心:将几个权值大的点尽可能的合并到一个集合中是更优的。集合中的点两两没有祖孙关系,说......
  • GYM102596L Yosupo's Algorithm【分治,支配对】
    给定平面上\(2n\)个点,每个点有坐标\((x_i,y_i)\),权值\(w_i\)及颜色\(c_i\)。所有点满足:若\(c_i=0\),则\(x_i<0\);若\(c_i=1\),则\(x_i>0\)。\(q\)次查询,每次给定\(L_i,R_i\),你需要选择两个点\(i,j\)满足如下条件:\(c_i=0,c_j=1\)。\(x_i<L,x_j>R\)或\(x_......
  • 刺络放血第一天的部分治症
    四络放血的常用部位。第一个。肘窝部也就是在我们的。这是什么曲池?对不对?曲池尺泽曲泽这一个范围。你记着刺刺穴永远用的不是一个穴位点,它用的是一个区域。就跟我们说这个。假如说这胳膊吧,这是不是肘窝区?这是不是一般都有条大街?这是指责。这边曲子我们刺血的时候说的是这窝部,然后......
  • 笔记重修计划一:斜率优化 dp & cdq 分治维护凸包(施工中)
    施工中,但是目前暂停施工。前言刷cdq分治的时候做到了这题,发现自己不是很懂这个东西,跑回去看自己几个月前写的斜率优化dp笔记,当时认为自己弄得很明白了,但现在看来简直就是皮毛,遂弄明白后写下此文,希望自己之后有更多启发时能继续充实这篇文章。若有不妥之处望指出。如果单调......
  • latex强大排版能力体现,多根号高度的联动调整
    简单根号内容:$\sqrt{2x^2*\frac{1}{3a}}$\\复杂根号内容:$\sqrt{2x^2}\sqrt{\frac{1}{3a}}$\\%明显看出多根号情形下,根号的这种调整是无能为力的,借助命令vphantom,使得对象占据本身的高度宽度为零\\复杂根号内容:$\sqrt{\vphantom{\frac{1}{3a}}2x^2}\sqrt{\frac{1}{3a}}......
  • 分治-平面最近点对问题
    oiwiki中该问题的讲解。1.P1257平面上的最接近点对基础款,暴力可过。2.P1429平面最近点对(加强版正常款,玄学版本也能过(题解第一个做法,不过最初没卡这种方法的话应该随机情况下能过绝大多数点)。分治解决,将集合每次分成两部分,两个部分本别先求出集合内部的最小点对的答案d......
  • 三位偏序,CDQ分治入门
    (我发现我最近dp没有进展,导致我开始刷水题了。。)cdp分治,我蓝书又又看不懂了所以我还是自己去找题目做的看了看,这个应该才算是真正的入门吧这里先放上一句我觉得非常重要的话吧CDQ分治有一个重要的思想——用一个子问题来计算对另一个子问题的贡献。看到最后我对这句话的理解......
  • 【学习笔记】边分治
    算法思想和点分治类似,边分治每次选一条边,考虑跨过这条边的路径贡献,为了保证复杂度,会让两边子树大小尽量接近。发现菊花图无论怎么分治都是无效的,考虑将原树三度化,具体做法是如果\(u\)有两个儿子,就新建一个节点连接第二个儿子,如果还有更多的儿子,就再新建节点与上一次新建的节......
  • 边分治
    namespaceBFZ{ intk=1,ssz,rt,tot; inth[N],dep[N],sz[N],vis[N]; vector<pair<int,int>>G[N]; structAB{ inta,b,c,n; }d[N*2]; voidcun(intx,inty,intz){ d[++k]={x,y,z,h[x]},h[x]=k; } voidrebuild(intx,intfa){ inttmp=0,lst=0......
  • 递归与分治
    一、初步递归1、递归特点函数自己调用自己存在直接递归和间接递归一定有退出条件2、递归三要素退出条件递归函数的定义最后的解3、递归优化记录重复的值(存在重复的值才记录)......