- HDU.5977.Garden of Eden(点分治)
- hihoCoder.1496.寻找最大值(高维前缀和)
- 北京八十中集训 12.20 例一.Triple(思路 计数)
- 北京八十中集训 12.20 例二.Manhattan(CDQ分治)
- Codeforces.150E.Freezing with Style(点分治 二分答案 单调队列)
- HDU.5381.The sum of gcd(线段树/莫队 RMQ)
- Codeforces.17E.Palisection(Manacher/回文树)
- 牛客练习赛38 E.出题人的数组(贪心)
- 牛客OI周赛7 提高组.C.小睿睿的方案(线段树)
- CF.464E.The Classic Problem(可持久化线段树 Hash)
- CF.1104D.Game with modulo(交互 二分)
- CF.1039D.You Are Given a Tree(根号分治)
- SRM577 Board Painting(最小割)
- SRM558 Surrounding Game(最小割)
- SRM590 Fox And City(最小割)
最新版会在这里更新。
HDU.5977.Garden of Eden(点分治)
(Description)
给定一棵(n)个点的树,每个点有一个颜色,颜色一共有(k)种。求有多少条路径包含(k)种颜色。
(nleq 10^5,quad kleq 10)。
(Solution)
点分治。状压颜色。记(cnt[s])表示状态为(s)的路径个数。
如果当前点状态为(s),那么就可以从(s)的补集以及(s)的补集的超集更新Ans。
但是这样复杂度当然爆炸。所以直接令(cnt[s])表示状态为(s)及(s)的超集的路径数。
每次合并一棵子树的状态时,枚举子树的状态(s_i),然后对于(s_i)的所有子集(s'),(cnt[s'])++。
代码见:https://www.cnblogs.com/WABoss/p/6036216.html。
还有用FWT做的社会人:https://www.cnblogs.com/Menhera/p/9514412.html, http://www.cnblogs.com/sclbgw7/p/9508235.html。
hihoCoder.1496.寻找最大值(高维前缀和)
(Description)
给定(n)个数(a_i),你需要找到两个数(a_i,a_j),使得(a_i*a_j*(a_i&a_j))最大。输出这个最大值。
(nleq 10^5,quad 0leq a_i<2^{20})。
(Solution)
考虑枚举(t=a_i&a_j)。那我们要对每个(t)求,满足(a_i&a_j=t)的(a_i,a_j)中,乘积最大的一对。
但是还是不好求啊。这个条件其实可以削弱,即我们对每个(t),求(t)为(a_i&a_j)的子集,乘积最大的一对(a_i,a_j)。显然不会丢失最优解。
(t)为(a_i&a_j)的子集,即(t)同时为(a_i,a_j)的子集。那么枚举(t)的超集,求最大的两个数做(a_i,a_j)就可以了。
可以用高维前缀和求,也可以对每个(a_i)直接枚举子集。是复杂度有差别吧?前者是(O(2^kk)),后者是(O(nlog a_i))。
北京八十中集训 12.20 例一.Triple(思路 计数)
(Description)
(Solution)
需要(O(n^2))解决。可以令(Two[v])表示(a_j+a_k=v, i-D<jleq k<i)的二元组((j,k))的个数,(One[v])表示(a_j=v, i-D<j<i)的(j)的个数,那么(Ans_i=sum_jOne[a_i-a_j]+Two[a_i-2a_j]+[3a_j=a_i])?
显然会有重复。每个(One)会被计算三次,所以给后两项带一个权值,让每个(Triple)恰好被计算三次,就可以直接去重了。
北京八十中集训 12.20 例二.Manhattan(CDQ分治)
(Description)
(Solution)
Codeforces.150E.Freezing with Style(点分治 二分答案 单调队列)
(Description)
(Solution)
二分答案(mid),然后点分治(当然点分治过程中二分答案更好些)。
对于以每个点为根的子树,求是否存在边数(len)在([L,R])之间且至少存在(frac{len}{2})条边权(geq mid)的路径。
把边权(geq mid)的边的权值设为(1),(<mid)的设为(-1),对于每种边数只需维护权值最大的路径即可。显然可以单调队列维护。但注意要先将子树按最大深度从小到大排序以保证复杂度。
复杂度(O(nlog^2n))。
HDU.5381.The sum of gcd(线段树/莫队 RMQ)
(Description)
给定长为(n)的序列(a_i)。(q)次询问,每次给定(l,r),求(sum_{i=l}^rsum_{j=i}^rgcd(a_i,a_{i+1},...,a_j))。
(n,qleq10^4, a_ileq10^9)。
(Solution)
莫队 RMQ:
把要求和的区间画出来。每次移动区间左右端点的时候,观察改变的会有什么。
假如原先区间是([4,6]),现在左端点移动到(3),当前答案会加上 (3,3;;3,4;;3,5;;3,6)的(gcd)。也就是固定(l),往右求(gcd)一直到(r)。
因为固定一个左端点(l),(a[l...n])这个后缀中的(gcd)只有(log)种,所以可以枚举(g=gcd),假设(g)出现在区间([l, r']),然后跳到(r')那里去,再从(r')跳到下一个(gcd)的位置,直到到达(r)为止。
这个过程中可以累加答案,复杂度是(log)的
从每个位置开始的第几个(gcd)出现在哪,还要RMQ+二分预处理一下。总复杂度(O(nlog^2n+nsqrt{n}log n))。
当然能想起Magic GCD这道题,预处理可以用单调栈,虽然复杂度还是(nlog^2n)的但显然常数小许多。
线段树:
同样把要求和的区间画出来,就很明显了。
比如设当前区间为([3,6])(左端点为(3)右端点为(6)),要求的区间有:
(3,3;;3,4;;3,5;;3,6\;;;;;;;4,4;;4,5;;4,6\;;;;;;;;;;; \,5,5;;5,6\;;;;;;;;;;;;;;;;; 6,6\)
以列为下标(上面分别是(3,4,5,6)),当询问左端点(l=3),右端点为(r)时,答案就是区间([3,r])的和。
而每次向左移动(l),会在上面增加一行。而以(a[l...n])中(gcd)只有(log)种,可以暴力算出这(log)种(gcd)以及它们对应出现的区间(还是同Magic GCD这道题),然后就可以直接区间加。
所以就是,把询问离线,按左端点从右往左处理。
复杂度(O(nlog^2n))。
Codeforces.17E.Palisection(Manacher/回文树)
(Description)
给定一个字符串(s)。求(s)有多少对回文子串,满足这两对回文子串在(s)中的位置有交集。
(|s|leq2 imes10^6)。
(Solution)
记回文子串总数为(sum),那(Ans=C_{sum}^2- ext{没有交集的回文子串对数})。
而没有交集的回文子串对数,就是(sum_{i=1}^{n-1} ext{以i结尾的回文串数}* ext{i后边的回文串数})。
以(i)结尾的回文串数(cnt_i)可以直接回文树,或是Manacher+差分求。(i)后边的回文串数就是(sum_{j=i+1}^ncnt'_j)。把串反过来求一遍(cnt_i)的后缀和就可以了。
因为(|s|)是(2e6),回文树要用边表存转移。
牛客练习赛38 E.出题人的数组(贪心)
(Description)
给定两个长为(n,m)的序列(A_i,B_i)。你需要把两个序列拼成长(n+m)的序列(C_i),要求原本同在(A_i)或(B_i)序列中的数在(C_i)中的相对顺序不变。求最小的(sumlimits_{i=1}^{n+m}i*C_i)。
(n,mleq10^5)。
(Solution)
先把整个(A)序列放在(B)前面。然后我们每次要找(B)的一个前缀扔到(A)里面去,且位置不能超过上一次放的那个前缀的位置。
假设选的(B)的前缀长度为(x),和为(s_1),放的位置离(A)的末尾距离为(y),这一段和为(s_2)。
那么当(y*s_1>x*s_2)时,这么做会优。移一下项就是(B)这段前缀的平均值更大。
而选的这段(B)的前缀应该是平均值尽量大的。
同时(C)序列最后是一段(A)+一段(B)+一段(A)+一段(B)...要让这些段的平均值递减。
所以我们就先把(A,B)分成一些平均值递减的段,最后按平均值大小归并就可以了。。
牛客OI周赛7 提高组.C.小睿睿的方案(线段树)
(Description)
给定一棵树及(m)条路径。求有多少条路径满足不完全包含这(m)条路径中的任意一条。
(n,mleq10^5)。
(Solution)
考虑求不合法的路径数。发现这些路径都是一个点在一段DFS序连续的区间中,另一个点在另一段DFS序连续的区间中。扫描线+矩阵求交即可。
复杂度(O(nlog n))。
CF.464E.The Classic Problem(可持久化线段树 Hash)
(Description)
给定一张(n)个点(m)条边的无向图,边权都是形如(2^{x_i})的形式((0leq x_ileq 10^5))。给定(s,t),求(s)到(t)的最短路。
(n,mleq10^5)。
(Solution)
考虑如何改进(Dijkstra)使得能做这道题。我们把(dis)数组用线段树存成(2^{a_1}+2^{a_2}...)的形式。
判断(dis)时,可以像字符串(Hash)一样,从高到低位在线段树上二分,找到第一个不同的位置,判断上面的大小关系。(Hash)可以直接用题目给的(seed=2, mod=10^9+7),当然最好还是自己再写个。
每次枚举一条边修改(dis)时,一个暴力的想法是,每次只改一位,就可持久化一下,在对应位置(+1),如果产生进位就暴力再在下一个位置(+1)。
这样复杂度是不对的,可以卡成(O(nmlog w))(然而网上都是这种办法...出题人竟然数据造水了,ssfd)。
官方题解的做法是,初始建两棵全(0)和全(1)的线段树,进位时可以直接替换节点,这样复杂度就是真的(O((n+m)log w))了。
事实上那种错误的做法有人在Tutorial的comments里提到过,他也意识到是错的了。
CF.1104D.Game with modulo(交互 二分)
(Description)
要求在(60)次询问内猜出一个数(a (1leq aleq10^9))。每次你可以询问((x,y) (0leq x,yleq10^9)),交互库会返回以下两个字符之一:
x
,如果((xmod a)geq(ymod a))。y
,如果((xmod a)<(ymod a))
(Solution)
考虑询问((x,2x))((xmod a)和(2xmod a)),如果(2x<a),显然结果是y
;(x>a),不好考虑;(x=a),结果是x
;(x<aleq2x),结果是x
。(为什么此时一定有(xmod a<2xmod a)呢...令(2x=a+b=x+x),因为(x<a),所以(x>b)。。)。
综上,如果我们依次询问((0,1),(1,2),...,(2^{29},2^{30})),我们可以找到一个((2^k,2^{k+1})),满足(2^k<aleq2^{k+1})。这需要(30)次二分(最后一次不需要)。记这两个边界为(l,r),即(l<aleq r)。
考虑在([l+1,r])中二分答案(x)。如果(x<a),显然有(lmod a<xmod a);如果(xgeq a),同样考虑拿(l)询问,有(lmod a>xmod a)(还是令(x=a+b),如果(bgeq l),那么(x>r)显然不对)。
这样需要二分(29)次,那么就OK啦。
为啥都写的那么简洁啊...还是我太菜...
CF.1039D.You Are Given a Tree(根号分治)
(Description)
给定一棵(n)个点的树。求最多可以选出多少条不相交的路径,满足这些路径含有(k)个点。对(kin[1,n])输出答案。
(nleq10^5)。
(Solution)
暴力是(O(n^2))的,即对于每个(k),(O(n) DFS)一遍,能合并出一条(k)个点的路径就合并,否则向上。这样贪心显然是对的((NOIP)...)。
注意到答案是随(k)增加递减的,且(k>sqrt n)时,答案的取值只有([0,sqrt n-1])这(sqrt n)种,我们可以二分每个值是(k)的哪个区间的答案。
需要做(sqrt n)次,每次复杂度(O(nlog n)),总复杂度是(O(nsqrt nlog n))的。
(kleqsqrt n)时,可以对每个(k)暴力,复杂度(O(nsqrt n))。
发现两部分的复杂度并不均衡,(kleq T)时复杂度是(O(Tn)),另一部分是(O(frac{n^2log n}{T})),所以取(T=sqrt{nlog n})时最优。
官方题解里有(O(nlog^2n))的做法...(据作者本人说)很不好写...
SRM577 Board Painting(最小割)
具体看这里叭,先不细整理惹。https://www.cnblogs.com/jefflyy/p/9679504.html
初始ans=总点数,每有一对点相邻,就可以减少1的花费,这样先算出一个答案。
然后把不合法的去掉。网络流每跑出1的流量,就表示有一对相邻的数不合法。这就是求割。要最小化去掉相邻点对的数量,使得方案合法。
SRM558 Surrounding Game(最小割)
神啊qwq。https://www.cnblogs.com/Blog-of-Eden/p/7783406.html
SRM590 Fox And City(最小割)
类似切糕的拆点qwq。https://www.cnblogs.com/zbtrs/p/8608842.html