record 1.15-1.19
CF1920 F2
我们考虑如何判定一个环路把整个岛给包住了。在 easy version 中,我们以所有岛为起点做八连通的 bfs,看一看能不能走到边界点。这个就是模拟题目中给我们的定义。
但是我们可以做得好一些。我们发现,对于一条合法的环路,从内部岛引出的任意一条射线都应该交环路奇数次。利用这一点,指定一条射线,比方说岛的上边界线。然后额外记录路径经过这条射线的次数的奇偶性。我们相当于询问无向图中 \(s\to t\) 路径上经过点权最小的点最大是多少。这个可以 kruskal 重构树简单做。
zroi Day5 B
这个题很有启发性!可惜场上觉得是 nt 计算几何就没有想。
首先我们有一个非常 naive 的 \(O(n2^n)\) 做法。我们枚举谁在多边形上,然后 \(O(n)\) check 并统计答案。
这个甚至不一定跑得过加了剪枝的 dfs。
我们考虑正经做法。dp。
枚举一个起点,我们自然地令这个点是这个多边形最低的一个点,其实这个无所谓。然后你二分答案,dp,记录上一个点和这一个点。这部分都比较好做,我们不多说了,复杂度是 \(O(n^4\log A)\),实在是太逊了。
我们非常想 dp 的时候只记录一个点,我们看看是什么东西阻碍我们这么做。首先判断是不是凸多边形,这个只需要把它剖成三角形,看每个三角形里有没有点,每次只需要知道一条边,不是瓶颈。然后,计算多边形面积,同样不是瓶颈。然后,计算外部点到顶点连的线段长度,由边不相交以及最小化 \(P\) 的要求,我们知道这事实上是给每个点划分了一个区域,区域内的点向顶点连边。而这个区域,是由相邻两条边的垂直平分线组成的,这个是我们的瓶颈。
这个形状实在是太丑了,我们划分一下。你把每条垂直平分线再移动到它附近的两个端点处,你发现现在每个点掌管的区域就是两个长方形和一个三角形。长方形的贡献完全由一条边确定,可三角形的贡献需要知道两条边。我们差分,考虑以三角形的顶点为原点极角排序,发现产生贡献的点是一个区间,那就可以差分了。注意最后一个点会有些细节。现在我们可以 \(O(n^3\log A)\)。
还有一个有意思的东西。我们考虑事实上我们要求的是 \(\max_{i=1}^n(best(i))\),我们原本的做法是老老实实求,但事实上我们可以 shuffle 一下整个序列,然后顺序枚举,每次先 check 当前点是否能达到当前最优解 \(ans\),不行直接跳,否则再在这个点处二分。
我们分析一下复杂度。每个点保底一次 check,接下来就是单调栈元素个数次二分。考虑单调栈元素个数的期望是多少,你计算值 \(i\) 出现在单调栈内的概率。
然后我不会算了,所以我只能估一估。
所以这个期望是 \(\log n\) 级别的。那我们这样做的复杂度就是 \(O(n^3+n\times n^2+\log n\log An^2)=O(n^3+n^2\log n\log A)\)。
但是我们是不是能给一个不依赖随机的做法。你考虑使用一个类似于倍增的算法,这样我们的 check 次数应该是 \(n+\sum_{i=2}^k \log(best_{p_i}-best_{p_{i-1}})\),其中 \(k\) 是单调栈大小。
而我们知道 \(best\) 是有一个上界的。所以相当于是有 \(\sum a_i=lim\),然后我们要估一个 \(n+\sum \log a_i=n+\log(\prod a_i)\le n+\log((\frac{\sum a_i}k)^k)=n+k\log(\frac{lim}k)\),通过求导,我们知道这个东西的级别是 \(O(n+\min(lim,n\log(\frac{lim}n)))\),在这道题中显然是 \(O(n\log(\frac{lim}n))\)。然后你发现没卵用,还是爆爆爆。
zroi Day5 C
这个,分块,感觉,很大。
我先说一下场上的想法。
首先通过做部分分,我们发现这个题最为关键的性质:如果进行了 \(q\) 次操作,我们可以在序列上找出来 \(q\) 个断点,相邻两个断点之间的所有东西,在这 \(q\) 次操作的过程中总是连着的,要么正序出现,要么逆序出现。这个是比较显然的,你考虑成连出来一条链,一次操作就是断一条边。
那么我们自然想到操作分块,块长为 \(B\),然后对序列分块,块个数是 \(B\)。我们现在需要处理每个块内部正逆序对数,以及两个块之间的贡献。场上我写的暴力树状数组做法,这个实在是有点逊,我们来精细一点。你枚举一个块,然后做一遍前缀和,然后扫一遍,这样做复杂度是 \(O(B(n+m))\)。预处理总复杂度 \(O(\frac qBB(n+m)+\frac qBn\log n)\)
但是你回答一次询问,需要 \(O(B^2)\),所以询问复杂度 \(O(qB^2)\)。
总复杂度 \(O(q(n+m)+\frac qBn\log n+qB^2)\le O(qn)\)。瓶颈在预处理上。我场上觉得这东西是不是就是正解=_=。
然后是 sol。
我们先考虑 \(m\) 不大的情况。这个我们可以考虑合并两个序列,记录每个颜色各有多少,容易 \(O(m)\) 合并,所以可以套一个平衡树,时间复杂度 \(O((n+q)m\log n)\),空间复杂度 \(O(nm)\)。但是出题人开了 128M,所以空间被卡了。
没关系,底层分块会出手。我们考虑当节点个数不超过一个阈值 \(B\) 的时候,直接暴力开一个 vector。分析一下,这样做的时间复杂度,一次 split 我们把底层节点暴力分裂,复杂度 \(O(B+B\log B+m\log n)\),一次 merge 正常进行。空间复杂度,我们最开始有 \(O()\)。呃呃,不是很懂,之后再分析这个。 让我分析一下。空间复杂度,最开始,所有 vector 大小是 \(O(n)\) 的,平衡树大小是 \(O(\frac nB)\) 的。每次操作,我们会最多会新建一个节点,但是新建的这个点它是一个小点,所以我们不会新开一个 \(O(m)\) 的数组,同时 vector 大小之和不变。所以我们知道,空间复杂度是 \(O(m\frac nB+q)\) 的。
我们取 \(B=m\) 可以得到一个时间 \(O(qm\log n)\) 空间 \(O(n)\) 的做法。我觉得是 \(O(n)\) 的,但是 sol 里说是 \(O(n\log m)\) 的。你考虑最开始的情况,这个时候其实最开始的最优应该是采用分治建树,然后我们得到一个 \(O(m\frac nm)\) 的结果。
我们注意到,预处理复杂度基本达到瓶颈了,但是这个询问里面,这个 \(B^2\) 非常刺眼,所以我们考虑在这上面优化。对于每个块,我们选择分治,经过不复杂的操作,我们可以在 \(O(len^2)\) 的时间内,把当前问题分治成两个子问题,这样列出方程就是 \(T(n)=2T(\frac n2)+O(n^2)\) 这个解出来是 \(T(n)=n^2\)。这样,我们可以做到好一点的复杂度,可以通过一个子任务。
然后我们发现我们现在对同一个问题,有两个不同做法,考虑一个类似于根号分治的东西,但是是我们手动分治的。
你对值域分块,块长为 \(A\),对于跨值域块的贡献,我们用平衡树,这个可以做到 \(O(q\frac nA\log n)\)。
对于值域块内部的贡献,我们操作分块,块长为 \(B\),使用第二个做法,我们预处理一个块内的复杂度降为 \(O(nA)\)(其实也可以分析成 \(O(A^2)\))。
总之他说处理一次询问的均摊复杂度是 \(O(\frac{n\log n}A+\frac{nA}B+B)\),取 \(B=\sqrt{nA},A=n^{\frac 13}\log^{\frac 13}n\) 可以得到 \(O(qn^{\frac 23}\log^{\frac 13}n)\)。
但是平衡树太逊了,你需要卡常。
我们替换成分块+分治。对操作按 \(A\) 为块长分块,合并仍然采用第一种的方法,做做做。
这个思路大概清楚了,但是复杂度分析还是有点不懂。
题目很神秘,给我这么一堆部分分我也想不出来正解。
UOJ 群里的一个数学题
对长度为 \(n\) 的由 \(\pm1\) 组成的序列,计数任意前缀和 \(\le k\) 的方案数。
我们考虑反射容斥,先枚举 \(s_n\) 是几。
你发现这两个东西都是连续的。其中第一个部分的下标取值范围在 \([0,\min(n,\frac{k+n}2)]\),第二个部分在 \([\frac{n-k-1}2,\min(n,k)+\frac{n-k-1}2]\)。
无论怎样,这个东西的形式,都是求若干个组合数前缀和。这个东西是没有封闭形式的,但根据原题给的条件,我们一般可以做得好一些。
[NOI2016] 优秀的拆分
我们考虑怎么计算这样的拆分数。这样的方法是很多的,比方说你可以枚举子串,你可以枚举一个串找到它的所有出现位置然后跟别人拼一拼,你可以枚举中间位置。
我们发现最后一个方法最简单,所以我们考虑最后一个方法。问题转化成求出一个数组 \(f_i\) 表示以 \(i\) 结尾的所有串中,多少个是可以拆分成 \(AA\) 这种形式的。
我们换一种角度思考,转成枚举一个 \(A\) 串,然后考虑它的出现位置,对于一次相邻不相交位置的出现,我们给一个贡献。
然后我想了想这个东西能不能直接扔到笛卡尔树上去做,发现这个东西十分困难。
然后我就摆了,看了 sol。
很妙的做法啊!但是我觉得我确实想不到。
考虑枚举这个 A 的长度,然后把所有是倍数的点都标记成关键点。我们知道最后 AA 一定恰好经过两个关键点。然后你把这个 AA 过关键点的情况给画出来,你发现我们只需要统计相邻两个关键点的 \(lcp,lcs\) 就可以了。
我又想了一下,感觉这个还是有一点苗头的。就是说,我们最暴力的做法就是枚举完 A 之后直接枚举起始位置,然后这个优化一下就是这个做法?
Luogu P4707
我们注意到,他想让我们算的其实就是 \(E(\min(k,\{T_1,\dots,T_n\}))\)。
这个不可能不容斥的。但是让我们顺手证一下 minmax 容斥的正确性。先给出形式。
我们考虑计算一个元素在右式中被计算了多少次。首先,对于排名 \(<k\) 的元素,它们根本不可能成为一个元素个数 \(\ge k\) 的集合 \(T\) 的 \(\max\),所以它们不会被计算。
考虑一个排名为 \(p\ge k\) 的元素 \(s\),它被计算的次数是
那就证完了。我们接下来就是要对每个集合求出来 \(\max(T)\),但是我们很讨厌这个形式,所以我们稍微变一下。
求 \(\min(T)\) 就舒服多了。而我们知道 \(E(\min(T))=\frac 1{sum(T)}\),所以我们现在关心的是 \((sum(T),|T|)\) 这样的二元组个数。我们知道 \(sum(T)\le m,|T|\le n\),然后 01 背包外层还要一个 \(n\),直接统计复杂度是 \(O(n^2m)\) 的,无法通过。
呃,不太会做了,看了 sol。
这个,很奇妙啊。我们发现每次转移的时候,\(|T|\) 都会 \(+1\),然后你发现 \(\binom{|T|}{n-k}=\binom{|T|-1}{n-k}+\binom{|T|-1}{n-k-1}\)。这样我们记录 \(n-k\) 个东西就行了。
[WC2016] 论战捆竹竿
我们关心的是最后能凑出来的长度都有谁。所以我们其实比较关心当前往上再接一根竹竿,长度能增加多少。首先很显然的一点是,这个可以增加的长度,就是当前字符串 \(t\) 前拼接 \(s\),这个字符串的 border,对应的 \(n-len\)。
那一个比较显然的结论就是说,我们每次增加的长度,只可能是最开始的那些 border。
那现在我们立刻得到了一个 \(O(\frac{nV}{w})\) 的做法,直接对这些数做 01 背包即可。
现在,问题变成了,给你一个递增序列 \(\{a_k\}\),问你 \([a_k,w]\) 中能凑出来多少数。
好了不会了,刚刚去看了一圈裴蜀定理,还是不会。看了 sol。
我们先说一个定理:一个字符串的 border 可以被拆分成不超过 \(\log |S|\) 个等差数列。
先证明一个引理:考察一个字符串的最长 border \(B\) 和任意一个长度超过一半的 border \(|A|\)。
我们注意到 \(|s|-|A|,|s|-|B|\) 都是 \(s\) 的周期,这就说明 \((|s|-|A|,|s|-|B|)\) 也是它的周期,这就说明 \(|s|-(|s|-|A|,|s|-|B|)\) 是它的 border,这就说明 \(|s|-(|s|-|A|,|s|-|B|)\le |B|\) 就是说 \(|s|-|B|\le (|s|-|A|,|s|-|B|)\)。这样,我们证明了 \(|s|-|B|\mid |s|-|A|\)。我们记 \(d=|s|-|B|\) 是一个周期,那就说明 \(kd\) 都是周期,说明 \(|s|-kd\) 都是 border,而这些 border 构成等差数列。
这里我们使用了一个定理,叫做弱周期定理。如果 \(p,q\) 都是 \(s\) 的周期,并且 \(|p|+|q|\le |s|\),那么 \((|p|,|q|)\) 也是 \(s\) 的周期。不妨令 \(|p|<|q|\),这里我们使用类似辗转相减法,考虑证明 \(q-p\) 也是周期。对于 \(p<i\le |s|-(|q|-|p|)\),\(s[i]=s[i-p]=s[i-p+q]\),对于 \(i\le p\),\(s[i]=s[i+q]=s[i+q-p]\)。
我们现在知道了超过一半的 border 构成等差数列,然后我们递归下去就好了。
那现在我们手头有一堆等差数列,严格来说应该是一堆 \(kd\) 这样的形式,我们要问它们能凑出来谁。(题解里面似乎都认为不是 \(kd\) 的形式,我不懂啊)。
那对于一个等差数列,我们进行同余最短路,注意到可以拆成若干个环,注意到不会跨过环上最小值更新,所以这个可以线性做。
考虑合并两个等差数列,把一个并到另一个上面去。注意到我们可以使用类似的方法线性更新。这样做复杂度是 \(\max(a,b)\)。
所以总复杂度是 \(O(n\log n)\)。
QOJ7759
这个题,非常厉害。看了 sol。
先说我的想法。首先这两个东西联系很紧,所以想拆开是不太可能的。看到相等的限制,我们第一反应是容斥了。但是容斥之后的形式并不是很好看。那我们还有另外一条路,你发现,如果说你把原序列中位置连续,值域也连续的段挑出来,这个东西在逆序列中也有很好的性质。但这种方法会导致你少算一些本来有贡献的地方。
然后我就不会了。
sol 是考虑对两维同时容斥,然后你考虑比方说原序列的第一个上升段,它在逆序列中长什么样子。你发现是逆序列中每个连续段取前面的一部分。倘若我们记 \(a_{i,j}\) 表示原序列的第 \(i\) 个段在逆序列中第 \(j\) 个段的长度,你发现这是一个一一对应关系。
我们找一下 \(a_{i,j}\) 的限制,你发现只有一条:上升段非空。所以相当于是要求这个矩阵,和是 \(n\),每行每列非空,每个数是非负整数。这是非常好做的,我们再次容斥即可。
但是,直接这么做是 \(O(n^4)\) 的。注意到两维独立,分开做即可。
QOJ6555
这个题,我之前听了一遍,比较掉线。今天自己想出来了。
我们一看这个点导出子图,非常不好啊,第一个想法肯定就是状压啊,肯定做不了啊。
第二个想法,看到要求偶数的点导出子图,那我们想到单位根反演,这个和是很好求的,接下来就看这个偶数减奇数好不好做。那我们肯定要找一些偶数奇数之间的性质,最好是一些转化。
本着这个主旨,我们考虑这个图当中的任意一个点 \(x\),你想看一看 flip 它的状态之后,这个解的奇偶性会不会改变。那你发现当 \(\sum_{(x,v)}a_v=0\) 时,不会改变,当 \(\sum_{(x,v)}a_v=1\) 时,会改变。所以说,对于后面那种情况,我们的奇偶时一一对应的,直接消掉了,我们只关心第一种情况。相当于原来有限制 \(\sum_{(u,v)}a_ua_v=0\),现在又来了一个 \(\sum_{(x,v)}a_v=0\)。这个我们直接暴力把后面这个方程解出来,代回原方程,就可以得到一个子问题。
这个直接做是 \(O(n^3)\) 的,不出意外的话可以 bitset 优化到 \(O(\frac{n^3}w)\)。
QOJ7303
这个题也很厉害。
首先观察到这个对 2 取模非常神秘,但是我们先不管。我们要求的是连通点导出子图,其中连通这个条件非常麻烦,我们想要限制这个东西的话,要么就暴力 dp,要么就做一个容斥一类的东西。那暴力 dp 肯定不行,我们想想容斥,常见的容斥就是钦定一个点所在的连通块有多大,然后做一些东西。但是这个的复杂度仍然无法承受。
我们尝试给每个方案分配一个系数,然后加加减减之后得到我们需要的东西。注意到我们要让连通块个数是 1,那么不妨记连通块个数是 \(x\),就要 \([x=1]\),这个常见的容斥方法是 \([x=1]=0^{x-1}=(1-1)^{x-1}=\sum_{i=0}^{x-1}(-1)^i\binom {x-1}i\)。我们考虑这东西有没有什么组合意义,你发现就是钦定 \(i\) 个连通块,所以这个等价于二项式反演。对于钦定类问题我们没什么好办法。
看了 sol,这个时候模 2 就出手了。我们构造 \(2^{x-1}\),首先这样是可行的。我们考虑它的组合意义,这相当于是把连通块分成了两个部分,并且钦定最小的连通块分到左边,并且要求两个部分之间不能有边。这个我们就可以 dp 做了,你考虑记录一个 state,记录一个 u,随便做做就行了。
QOJ2566
对于这种东西,我们的一个常见思路是给它找一个组合意义。你比方说,这个逆序对个数的 \(m\) 次方,就可以理解成我们有序,可重复地钦定若干对逆序对,然后问你满足这个条件的序列有多少。这个东西可能能做,但是一看就有一堆分讨。你哪怕用 string 数转成下降幂再转组合数,也是一样的。
那我们还有一个想法,就是说,排列跟前缀逆序对序列是一一对应的,那我们就变成你有一个序列 \(x_n\),满足 \(x_i<i\),问你 \((\sum x_i)^m\)。
这东西不能拆开,找组合意义,也有点困难。所以不太会做。
好吧看了 sol 是生成函数。让我用生成函数推一推。
而我们知道,
这个就是我们想知道的。但是你发现 \(F(e^x)\) 并不好求,所以我们考虑一个两边同时 ln,在这之前需要做一些变换。
对右边取 ln
考虑记 \(G(x)=\ln(\frac{1-e^x}x)\),后面那个就直接就是这个,前面那个是 \(\sum_p G(px)=\sum_p\sum_i g_i(px)^i=\sum_ig_ix^i\sum_pp^i\),这个后面是个自然数幂和。这些都是可以做的。
我们把答案完整写出来。(方便我写代码)
我们写这个题,主要是想实现一下 \(n^2\) 的多项式操作(正好三个),所以我们并不想写别的东西,所以我们的 \(n!\) 是乱搞过的()。
QOJ5357
看了 sol 好像还是不是很明白。
我们对点分树计数,最简单的办法是状压,但是状态数是树上连通块个数,这显然不行。
那我们接下来可以考虑一些容斥或者什么东西,但在这之前,让我们先想想点分树的一些性质。
一个重要的观察是,点分树其实是一种给节点排序,按照顺序依次选取每一个点出来当所在连通块的根节点的东西。但问题出在,不同的序可以对应于同样的结果,我们有一个想法是钦定一个合适的序,或者说容斥一下。
你考虑一棵树的点分树,如果你断开其中一条边 \((u,v)\),那么你可以得到唯一对应的两棵点分树。你考虑这个过程反过来做合并,发现这个相当于是先钦定两个根中的一个当最终的根,然后把根的一个子树和另外一棵树递归合并。这个相当于是对 \(u,v\) 到根的链做一个任意合并,我们只需要记录 \(u,v\) 到根的链长度即可。
不是,我现在明白了,但是这做法怎么想出来的啊???
[十二省联考 2019] 希望
那就是希望。
即便需要取模,也是光明。
终于做到这个题了。
AGC029 F
感觉非常神秘的跟网络流没什么关系的题。
考虑怎么限制一棵树,你发现他给了 \(n-1\) 条边,所以我们只需要限制这整个图连通就可以了。然后就误入歧途。
你考虑对于最终结果的一棵树,我们直接钦定 \(1\) 是根,这样每个其它点都有一个唯一的父亲,我们考虑把每个点匹配到它和它父亲的连边上,这个相当于是每个点去匹配一个包含它的集合。
然后你发现,当你钦定完这个匹配之后,你接下来的连边方案其实是唯一确定的。肯定是把所有包含 \(1\) 的集合选出来,然后让它匹配的点向 \(1\) 连边,然后继续循环这个过程。但问题出在,有可能连着连着,发现没有集合可以连上来了。这个时候,你发现相当于有 \(n-m\) 个集合只包含 \(n-m\) 个数,那这样这个部分一定就成环了。肯定不合法。
所以我们找到任意一个匹配,然后顺着做,能做完就做完了,做不完就不合法。
这个,我们是先考虑答案的性质,找到了一种决策数量更少的决策方法,然后去寻找这种决策方法什么时候合法,发现比较巧合,直接做就可以。
为什么呢?
QOJ4513
这个感觉比之前的都要简单一些。
如果没有每个点度数相同的限制,我们可以跑上下界就做完了。
那我们直接枚举每个点的经过次数,然后这样也是可以建出一个上下界的图的。
但是这样做复杂度会爆炸。
我们考虑,要求每个点经过次数相同,其实相当于是在说这个图要有一个欧拉路径。我们问的其实就是每个边可以被复制,复制完之后,这个图要有欧拉路径。
我们一个自然的问题是这个东西具不具有单调性,但是仔细思考之后发现单调性等价于这个图要存在哈密顿回路,这显然我们没办法知道。
看了 sol。
额,我们要知道的其实不是哈密顿回路,是一个稍微弱一点的东西:能否用若干条回路把所有点恰好覆盖一次。这个其实是可以做的,我们用网络流就可以解决。
同时,如果说我们能找到一个 \(d\) 的解,因为这个时候这张图是一张度数为 \(d\) 的正则二分图,所以我们可以找到一组完美匹配,我们直接加一轮这个完美匹配的点,就可以找到一个 \(d+1\) 的解。所以有解就一定有 \(d+1\) 的解。
那现在我们只需要跑一次上下界就可以解决这个问题了,最后跑一边欧拉路就行了。
可是这样复杂度还是有一点问题,虽然不是很好卡。
我们发现,如果存在解,那么一定存在完美匹配。并且,我们可以把解分割成恰好 \(d\) 个完美匹配,那显然的一点是每个边都要在至少一个完美匹配中出现。如果我们求出了这些完美匹配,我们只需要把这些东西加起来,就可以得到解。
我们先跑一次网络流,求出一组完美匹配。然后,如果我们想求出一条非匹配边 \((u,v)\) 的完美匹配,我们从它的右部点开始 dfs,交替走匹配边和非匹配边,得到一棵 dfs 树,然后找到左部点所在的位置,你发现这里有一个跟根相连的环,你把这个环 flip 即可。
因为对每个右部点,只需要 dfs 一次,所以总复杂度是 \(O(Tnm)\) 的。

浙公网安备 33010602011771号