RE:ゼロから始める AFO 生活

新建这篇博客的时候发现自己在NOI之后只发过两三篇博客,而且都基本上没什么实质性内容。
果然是巨大混混人啊。
本文承接上篇(不过好像烂尾了),旨在记录一些有趣(?)的内容。

12.23

北大集训过去好些天了。
对退役这件事情几乎无感,IOI也并非自己所坚信的道路。
但这也只是逃避的说辞罢了。
不过有一说一,退役二字本身还是很让人沮丧的。至少不能够把这种挫败感带到机房传染给学弟们。

以后还是会做点题什么的,毕竟在近一两年里总还是会被打上,或者说需要依赖于这引以为傲的OIer标签的。
当然也会有些别的计划,在此就不多提及了。


下午补了USACO的题。T3那个数数题在北大集训前鼠就跟我讲过但好像当时......根本没有脑子?

「USACO 2019.12 Platinum」Greedy Pie Eaters

首先可以认为每个区间都对应一头牛(若不存在可以认为牛的体重为\(0\)),记\(A_{l,r}\)表示区间\([l,r]\)对应的牛的体重,显然最终会选出恰好\(n\)头牛,每头牛吃恰好一个派。

考虑区间dp。枚举区间\([l,r]\),并枚举区间内最后一个被吃掉的派\(k\)

\(f_{l,r}=\max_{l \le k \le r}\{f_{l,k-1}+f_{k+1,r}+g_{l,k,r}\}\),其中\(g_{l,k,r}=\max_{l \le x \le k \le y \le r}A_{x,y}\)

\(g\)可以和\(f\)一起算,即\(g_{l,k,r}=\max\{g_{l+1,k,r},g_{l,k,r-1},A_{l,r}\}\),可以把其中一维用滚动数组优化掉。

code

「USACO 2019.12 Platinum」Bessie's Snow Cow

直接用std::set维护每种颜色的子树并,再安排个树状数组支持区间加区间求和就完事了!!1

code

「USACO 2019.12 Platinum」Tree Depth

一件(众所周知的)事情是设\(f_{n,k}\)表示逆序对数为\(k\)\(n\)阶排列的数量,那么其生成函数\(F_n(x)=\sum_{k\ge 0}f_{n,k}x^k\)满足

\[F_n(x)=\prod_{i=0}^{n-1}\sum_{j=0}^{i}x^j=\prod_{i=1}^{n}\frac{1-x^i}{1-x} \]

大致含义是考虑排列的生成方式,每次在一个\(i\)阶排列的末尾添加一个新的数字,根据新添加的数字与原数的大小关系可以得到逆序对数的增量。

另一件(众所周知的)事情是在考虑排列中某个位置在对应的笛卡尔树上的期望深度时,常常根据期望的线性性,转化成考虑其余每个位置在笛卡尔树上作为这个位置的祖先的概率。具体的,一个\(n\)阶排列中,\(i\)作为\(j\)在笛卡尔树上的祖先的充要条件为:\(p_i\)是区间\([i,j]\)(或区间\([j,i]\))中的最小值,而这个概率显然是\(\frac{1}{|i-j|+1}\)

回到原问题。考虑枚举\(i,j\),计算有多少逆序对数为\(k\)的排列满足\(i\)\(j\)在笛卡尔树上的祖先。相当于是在插入\(i\)位置时强制其为当前最小,也即对于上述的生成函数\(F_n(x)\),把\(\prod\)\(\sum_{k=0}^{|i-j|}x^k\)项改为\(1\)或者\(x^{|i-j|}\)(根据\(i,j\)的大小关系,会发现当\(i<j\)时插入\(i\)不会贡献逆序对,\(i>j\)会贡献恰好\(i-j\)个逆序对)。

只需要计算出\(F_n(x)\),然后每次除掉一个\(\frac{1-x^i}{1-x}\)即可。

code


晚上口胡了下PKUWC。jlsnb!

12.24

今日不更。

12.25

今日不更。

12.26

zsy啊zsy,你不能再这样颓废下去了呀。

更一些退役后的写水题记录。

「PA 2019」A + B

咕咕

「PA 2019」Muzyka pop

先假想有一棵包含了\([0,m]\)所有数的二进制\(\text{Trie}\),那么就可以实现一个很简单的动态规划:记\(f_{x,l,r}\)表示把\(b_l,...,b_r\)选在\(\text{Trie}\)树上\(x\)节点的子树里的最优解,转移时枚举\(k \in [l-1,r]\)表示把\(b_l...b_k\)放到\(x\)的左儿子,剩下的放到右儿子,那么此处便产生贡献\(a_{k+1}+...+a_r\)

可以发现这棵二进制\(\text{Trie}\)除了表示\(m\)的叶子到根的那一条链外每个点的子树都是完全二叉树,因此在动态规划中只需要记录\(x\)的深度以及\(x\)在不在\(m\)到根的链上即可,时间复杂度\(O(n^3\log m)\)

code

「PA 2019」Desant

朴素状态压缩动态规划的复杂度是\(O(n2^n)\),需要记录每一个数字是否被选取。但直观来想,随着选取的数字越来越多,我们不再那么关心每个数字是否被选取,而只关心某些值域区间里被选取了多少数字。

对于每个\(i \in [1,n]\),将\(a_i,a_{i+1},...,a_n\)从小到大排序,设排序后为\(b_1,b_2,...b_{n-i+1}\),我们只关心每个\((b_j,b_{j+1})\)区间内被选了多少个数字(\(j \in[0,n-i+1]\),定义\(b_0=0,b_{n-i+2}=n+1\))。因此,在考虑完前\(i-1\)个数的选取后,我们只需要在状态中记录前述的每个区间被选取了多少数字即可,这个状态总量显然为\(\prod_{j=0}^{n-i+1}(b_{j+1}-b_j)\)

考虑一下总状态数。可以发现状态数的总量不超过\(\sum_{k=1}^n\max\{\prod_{i=1}^ka_i|a_i \in \mathbb{N}^*, \sum_{i=1}^ka_i = n+1\}\)。众所周知取尽量多的\(3\)是最优的,因此在\(k=\frac{n+1}{3}\)时的最大值为\(3^{\frac{n+1}{3}}\)。所有\(k\)的最大值之和不太会分析,但显然不超过\(O(n3^{\frac{n+1}{3}})\)。鉴于状态转移是\(O(1)\)的,复杂度还算可以接受。

code

「PA 2019」Trzy kule

先小学生容斥一下变成求一个/两个/三个串同时满足限制。

一个串满足限制答案就是\(\sum_{i=1}^r\binom{n}{i}\)

两个串满足限制,可以把第一个串变为全\(0\),记第二个串有\(A\)\(0\)\(B\)\(1\),答案是$$\sum_{\substack{a+b\le r_1\a+B-b\le r_2}}\binom{A}{a}\binom{B}{b}$$

可以\(O(n)\)统计答案。

三个串满足限制,同理把第一个串变为全\(0\),记后两个串\(00/01/10/11\)组合各有\(A,B,C,D\)个,答案是$$\sum_{\substack{a+b+c+d\le r_1\a+b+C-c+D-d\le r_2\a+B-b+c+D-d \le r_3}}\binom{A}{a}\binom{B}{b}\binom{C}{c}\binom{D}{d}$$

枚举\(c,d\)后发现\(a,b\)有形如\(a+b \le x, a+B-b \le y\)的限制,暴力二维前缀和即可,复杂度\(O(n^2)\)

有 点 卡 常

update:好像直接\(2^n\)减去不合法(全部超过)就行了,我是个麻瓜。

12.27

今日不更。

12.28

今日不更。

1.6

我觉得日更这件事情可能不太适合我。兴许可以尝试一下周更?

「BalticOI 2019 Day2」奥运会

gzy大神教我做的题。

首先有一种想法是直接枚举每场比赛所有参赛者的最高得分,并计算方案数,然后拿这个方案数与给出的那个\(C\)比较。但这样的复杂度可能是错的(至少我不能证明它是对的),因为方案数可能为\(0\),因而无法保证遍历到的状态不会超过\(C\)种。

一件奇怪的事情是考虑对于任何一种\(k\)个参赛选手的集合,求一个这\(k\)个选手的排序。可以采用的一种策略是:把第一场比赛得分最高的排在第一位,剩下的人中第二场比赛得分最高的排在第二位,以此类推。

考虑怎么求最优解。一种可行的策略是,先选第一场比赛得分最高的,再在剩下的人中选第二场比赛得分最高的,以此类推。显然这个贪心选取的顺序是符合上述排序的。求出最优解后,不难把剩下的所有方案根据与当前方案的\(lcp\)划分成\(k\)类,每一类都相当于固定了方案的一个前缀,且要求这个前缀的下一位不能是某个选手。而根据前面讲的那个排序,会发现一个长度为\(j\)的前缀一定会确定前\(j\)场比赛的最高得分,也就是说限制一个固定前缀的下一位不能填原本的最大值等价于限制了这个原本的最大值再也不能出现。因此就可以用一个bitset维护尚可以出现在方案中的选手。

因此,搜索的状态需要记录如下信息:一个被固定的前缀,尚可以选的集合,以及权值。状态的权值应被定义为这个状态能给出的权值最大的方案的权值,计算出这个权值可以使用上述的贪心,紧接着便可以再根据剩余与当前方案的\(lcp\)划分成不超过\(k\)个子状态。

复杂度大概是\(O(nk^2C)\)

code

「POI2019 R1」Przedszkole

激 情 三 合 一

\(n \le 15\)。观察到答案是关于\(k\)的一个\(n\)次多项式,因此可以直接算出\(k=0,1...n\)的答案后插值。计算一个\(k\)的答案相当于是做独立集的子集卷积的\(k\)次方,这个可以很轻易地在\(O(2^nn^3)\)时间复杂度内计算出来。

\(m \le 24\)。直接暴力容斥每条边两端点是否强制相同,用并查集维护。复杂度\(O(2^m)\),可能还带个并查集的复杂度啥的。

每个点度数为\(2\)。那么图就是若干个环,而一个长度为\(l\)的环的色数多项式是\((x-1)^l+(-1)^l(x-1)\),然后不同的环长种数显然是\(O(\sqrt n)\)的,把环长相同的合并在一起算,复杂度为\(O(q\sqrt n)\)

code

1.14

周更\((\times)\)
半月更\((\times)\)
随缘更\((\surd)\)

Codeforces 736D. Permutations

给定一张两侧各\(n\)个点,共\(m\)条边的二分图,保证其完美匹配个数为奇数。对于二分图的每一条边,询问将这条边删去后,剩下的二分图的完美匹配数是否仍为奇数。
\(1 \le n \le 2000, n \le m \le \min(n^2, 5\times 10^5).\)

\(a_{i,j}\)表示二分图中是否存在一条从\(i\)连向\(j'\)的边(存在为\(1\)不存在为\(0\)),那么二分图完美匹配数为奇数等价于\(\sum_p\prod_{i=1}^na_{i,p_i} \equiv 1 \mod 2\)。由于\(-1 \equiv 1 \mod 2\),所以也等价于\(\det(A) \equiv 1 \mod 2\)

再考虑删除一条边后的完美匹配数怎么计算。容斥,考虑计算强制这条边在完美匹配中的匹配数,会发现这恰好是\(a_{i,j}\)的余子式\(M_{i,j}\),而我们只关心\(M_{i,j}\)的奇偶性。同样因为\(-1 \equiv 1 \mod 2\),我们只需要计算\(a_{i,j}\)的代数余子式\(A_{i,j}=(-1)^{i+j}M_{i,j}\)

求代数余子式只需要求出\(A\)的伴随矩阵\(A^*\),而由于\(AA^*=A^*A=\det(A)I\),因而\(A^*=\frac{\det(A)I}{A}\),矩阵求逆即可。由于运算均是为\(\mathbb{F}_2\)下进行的,可以压位优化,最终复杂度为\(O(\frac{n^3}{\omega})\)

code

Codeforces 891E. Lust

给定\(n\)个数\(a_1,a_2,...,a_n\)和一个初值为\(0\)的计数器\(cnt\),执行以下操作\(k\)次:
\(1...n\)中等概率随机选择一个数\(x\),令\(cnt\)加上\(\prod_{i \neq x}a_i\),然后把\(a_x\)\(1\)
\(k\)次操作后计数器\(cnt\)的值的期望模\(10^9+7\)
\(1 \le n \le 5000, 1 \le k \le 10^9.\)

观察发现每次令计数器加上的值实际上是\(\prod_ia_i-\prod_ia_i'\)

因此\(k\)次操作后计数器的值至于每个\(x\)被减了多少次有关,与减的顺序无关。也即,设\(a_i\)最终被减了\(b_i\)次(\(\sum_i b_i = k\)),那么计数器的值即为\(\prod_ia_i-\prod_i(a_i-b_i)\)。前者是常数,只考虑计算后者。

设指数型生成函数\(F_a(x)=\sum_{i \ge 0}\frac{a-i}{i!}x^i\),那么答案就是\(\frac{k!}{n^k}[x^k]\prod_iF_{a_i}(x)\)

不难发现\(F_a(x)=e^x(a-x)\),因此答案可以写成\(\frac{k!}{n^k}[x^k]e^{nx}\prod_i(a_i-x)\)

因此只需要\(O(n^2)\)求出\(A(x)=\prod_i(a_i-x)=\sum_{i=0}^nc_ix^i\),那么答案就是\(\sum_{i=0}^n\frac{k^{\underline{i}}}{n^i}c_i\)

code

1.16

「PA 2019」Podatki drogowe

把权值看做一个\(n\)进制数,由于树边只有\(n-1\)条,因此显然不会进位。对一条路径开桶记录权值为\(n^i\)的边出现了多少次,那么比较两条路径的权值大小等价于反着比较两个桶的字典序大小。

对树进行点分治,使用可持久化线段树+哈希的方式维护桶(具体的,对桶的每个位置随机一个权值,线段树维护桶的对应区间内的权值和,比较两棵线段树时根据右子树的权值和判断两个桶的\(lcp\)是否大于\(mid\)),这样可以实现\(O(\log n)\)地比较两条路径的字典序大小。

考虑如何求第\(k\)大。理想的做法是二分:点分后会将会得到\(O(n\log n)\)棵线段树,它们会被分为\(O(n)\)个组,每个组里的线段树两两组成一条完整路径,贡献还需乘上一个\(\pm 1\)的容斥系数,表示在点分过程中是否被强制选自重心的同一棵子树。预先对每一组内的线段树进行排序(使用上述\(O(\log n)\)的比较),对于一条确定的路径\((u,v)\),可以使用two-points在\(O(m\log n)\)的时间复杂度内求出一个大小为\(m\)的组内有多少条路径\(\preceq(u,v)\)。因而,若能够实现快速找出二分中\(mid\)对应的路径,可以在\(O(n\log^2n)\)的时间复杂度内对一个给定的\(k\)求出答案。

然而现实的问题是无法找出二分中\(mid\)对应的路径。可以采取随机的方式:答案一定是在\(O(n\log n)\)棵线段树中选出两棵组合而成,维护两条路径\((u_l,v_l)\)\((u_r,v_r)\),每次随机找出一条路径\((u_{mid},v_{mid})\)满足\((u_l,v_l)\preceq(u_{mid},v_{mid})\preceq(u_r,v_r)\)(这个过程与前述的two-points部分几乎完全一致)并计算有多少条路径\(\preceq(u_{mid},v_{mid})\)。可以证明随机次数为\(O(\log n)\)

值得注意的是,点分后得到的\(O(n\log n)\)棵线段树需要去重,在随机若干次后满足\((u_l,v_l)\preceq(u_{mid},v_{mid})\preceq(u_r,v_r)\)\((u_{mid},v_{mid})\)数量较少时,需要暴力拿出所有\((u_{mid},v_{mid})\)后排序并二分。否则会被某些特殊数据(比如说边权全相等的菊花)卡掉。

更多细节可以参考代码。

code

1.25

又咕咕咕好几天了(捂脸)

今天是庚子鼠年的第一天,祝大家新年快乐啦!新的一年要继续努力哟,加油干奥利给!

近来疫情形势严峻,希望看到这篇文章的你一定要出门戴口罩,记得勤洗手,勤开窗通风,少去人流密集的场所,宅在家里闷声大发财才是坠吼滴!

figure1. 戴上了口罩的有马君

1.26

补了USACO的题。

「USACO 2020.1 Platinum」Cave Paintings

同行且四连通的格子的状态必然是相同的,可以缩成一个点。

对于关系“若\(x\)是水则\(y\)必须是水”连边\(x \to y\),会发现连成了一片有向森林,因此直接树型\(dp\)就好了。

具体地,记\(f_x\)表示\(x\)子树内的方案数,则\(f_x = 1 + \prod f_y\)\(y\)\(x\)的儿子)。

代码实现中可以不显式地把树建出,而是使用并查集来维护树结构。

code

「USACO 2020.1 Platinum」Non-Decreasing Subsequences

先考虑怎么计算\([1,n]\)的答案。考虑动态规划,记\(f_{i,j}\)表示考虑了前\(i\)个位置,不下降子序列的末尾元素为\(j\)的方案数。对于转移,有\(f_{i+1,a_{i+1}}=\sum_{j=1}^{a_{i+1}-1}f_{i,j}+2f_{i,a_{i+1}},f_{i+1,j}=f_{i,j}(j \neq a_{i+1})\)

不难发现上述动态规划可以写成矩阵的形式。记

\[F_i=\begin{bmatrix}f_{i,1}&f_{i,2}&\cdots&f_{i,k}\end{bmatrix} \]

\[T_x=\begin{bmatrix} 1 & & & 1 & & \\ &\ddots & &\vdots & & \\ && 1& 1\\ && & 2 &&\\ &&&& 1 && \\ &&&&& \ddots& \\ &&&&&& 1 \end{bmatrix}\]

(其中那个\(2\)在第\(x\)\(x\)列)

\(F_{i+1}=F_iT_{a_{i+1}}\)。因此询问\([1,n]\)的答案为

\[\begin{bmatrix}1&0&\cdots&0\end{bmatrix}T_{a_1}T_{a_2}\cdots T_{a_n}\begin{bmatrix}1\\1\\\vdots\\1\end{bmatrix} \]

现在考虑对于一般的询问\([l,r]\)求答案。求出\(T_x\)的逆矩阵\(T_x^{-1}\),发现它长这样

\[T_x^{-1}=\begin{bmatrix} 1 & & & -\frac 12 & & \\ &\ddots & &\vdots & & \\ && 1& -\frac 12\\ && & \frac 12 &&\\ &&&& 1 && \\ &&&&& \ddots& \\ &&&&&& 1 \end{bmatrix}\]

因此,可以考虑预处理

\[x_i=T_{a_1}T_{a_2}\cdots T_{a_i}\begin{bmatrix}1\\1\\\vdots\\1\end{bmatrix} \]

\[y_i=\begin{bmatrix}1&0&\cdots&0\end{bmatrix}T_{a_i}^{-1}T_{a_{i-1}}^{-1}\cdots T_{a_1}^{-1} \]

于是一组询问\([l,r]\)的答案就是\(y_{l-1}x_r\)

由于矩阵特殊,右乘\(T_x\)或左乘\(T_x^{-1}\)均可以在\(O(k^2)\)的时间复杂度内完成,因此最终的时间复杂度为\(O(nk^2+qk)\)

code

「USACO 2020.1 Platinum」Falling Portals

一个(比较显然)的结论是任意两点间存在一条经过不超过一个中转点的最短路,因此暴力做法就只需要枚举这个中转点是哪个点就好了。

先考虑\(a_{q_i}<a_i\)的情况。会发现中转点\(x\)必然满足\(x\ge \max(i,q_i)\)\(a_x \ge a_i\),而选定了\(x\)后答案是\(\frac{a_x-a_{q_i}}{x-q_i}\)。可以证明使答案取最小值的\(x\)一定在下凸壳上,因此按照\(a_i\)从大到小枚举\(i\),维护所有满足\(j \ge i, a_j \ge a_i\)的点\((j,a_j)\)的下凸壳,对于查询就只需要在下凸壳上二分找到使目标函数取到最小的位置即可。

对于\(a_{q_i}> a_i\)的情况,只需要相对应地按\(a_i\)从小到大枚举\(i\),维护\(\{(j,a_j)|j \le i, a_j \le a_i\}\)的上凸壳,查询同样二分即可。

code

2.15

本来打算等到下次出门再更博的,但是发现貌似遥遥无期?

更一点JOI 2020 Final的题。

「JOI 2020 Final」只不过是长的领带

显然匹配方式是排序后对应匹配,只需要说明当存在交叉匹配时交换两者一定不会变劣即可。

\(a_i\)\(b_i\)分别排序,那么\(b_i\)将可能匹配\(a_i\)或者\(a_{i+1}\)。不难写出当选择\(a_k\)删除时,答案为\(\max\{0,\max_{j<k}\{a_j-b_j\},\max_{j>k}\{a_j-b_{j-1}\}\}\),维护\(a_j-b_j\)的前缀最大值以及\(a_j-b_{j-1}\)的后缀最大值即可。

code

「JOI 2020 Final」JJOOII 2

问题等价于选出一个满足条件的子序列,最小化首尾距离。那么确定了首位之后就可以贪心往后选了。

code

「JOI 2020 Final」集邮比赛 3

显然任意时刻已访问的范围是一个包含起点的连续区间,由于包含起点,那么记录这个区间就只需要记录从原点出发向两侧延伸的长度即可。

\(f_{i,j,k,0/1}\)表示目前已经考虑过前\(i\)个以及后\(j\)\((n-j+1...n)\)目标点,目前答案为\(k\),且当前位置在第\(i\)\(/\)\(n-j+1\)个目标点上的最早时间。转移只需要考虑下一步是去\(i+1\)还是去\(n-j\)即可。

code

「JOI 2020 Final」奥运公交

建出四棵(从\(1\)号点出发、到达\(1\)号点、从\(n\)号点出发、到达\(n\)号点)最短路树。

若翻转的边不再任意一棵最短路树上,考虑翻转后的最短路,显然要么是原最短路,要么必经过翻转的边,除了翻转的边之外剩余部分一定是沿着最短路树走,因此可以\(O(1)\)计算出新的最短路。

若翻转的边在某一棵最短路树上,考虑到这样的边只有\(O(n)\)条,暴力即可。

由于一次计算最短路的时间复杂度是\(O(n^2+m)\),因此该算法的总时间复杂度为\(O(n^3+nm)\)

code

「JOI 2020 Final」火灾

\(a \to b\)表示某个区域的火势上一时刻为\(a\)而这一时刻为\(b\),那么在整个过程中,本质不同的\(a \to b\)只有不超过\(n\)种,这是因为一个数只会被前面第一个比它大的数给覆盖掉。

对于一组询问\(t,l,r\),令答案初值为\(\sum_{i=l}^rS_i\),接下来只需要统计变化的总量,也即,只需要统计所有\(a \to b\)带来的\(b-a\)之和。

求出\(L_i=\max\{j|j<i,S_j>S_i\},R_i=\min\{j|j>i,S_j>S_i\}\)

可以发现上述的所有\(a \to b\)其实都是\(S_i \to S_{L_i}\)的形式。

考虑\(S_i \to S_{L_i}\)会在哪些时刻哪些位置发生,会对哪些询问的答案产生影响。

结论是,对于\(\forall j \in [i,R_i)\),上述过程会在第\(j-L_i\)时刻发生,会使得满足\(p \in [i,R_i), t \ge p-L_i\)\(S_p(t)\)的值加上\(S_{L_i}-S_i\)

如果把\(S_p(t)\)放在二维平面上,不难发现受到影响的区域是一个直角梯形。至此,问题转化为给出二维平面上的若干直角梯形进行范围加法,求某一行的区间和(前缀和)。

首先可以把直角梯形差分成两个三角形,我们用\((\alpha,\beta,\gamma)\)表示一个\(\{S_p(t)+=\gamma|p \ge \alpha, t \ge p - \beta\}\)的修改三角形,上述的直角梯形差分后得到两个三角形\((i,L_i,S_{L_i}-S_i)\)以及\((R_i,L_i,S_i-S_{L_i})\)

对于三角形\((\alpha,\beta,\gamma)\),考虑它对于\(t \ge \alpha\)的询问的影响(在这里,需要对于修改三角形以及询问按照\(\alpha/t\)排序)。实际上,对于询问\((t,x)\)的贡献为\(\gamma(\min(x,t+\beta)-\min(x,\alpha+\beta-1))\)(这里也可以看做是对于三角形左边界的一个差分)。

考虑怎么把这样的问题转化到我们熟练掌握的数据结构问题上。考虑一个简单的问题:前缀加法,前缀求和。假设一共有\(m\)\((a_i,b_i)\)表示要将前缀\(a_i\)全部加上\(b_i\),此时若询问\(c_i\)的前缀和,得到的答案会是\(\sum_ib_i\min(a_i,c_i)\)

应用到本题,把\(\min(x,t+\beta)\)写成\(t+\min(x-t,\beta)\),会发现两者均是上述的形式,因此使用支持前缀加法前缀求和的数据结构维护即可。多出来的\(+t\)大可不必考虑,因为在做前缀相减的时候会被恰好抵消。

code

3.1

到三月了呢。

「USACO 2020.2 Platinum」Delegation

二分答案\(K\)。对于一个有\(x\)个儿子的节点\(u\),它需要合并产生至少\(\lfloor\frac x2\rfloor\)条完整的路径,并可能留下半条路径继续延伸向\(u\)的父亲(注意当\(x\)为偶数时也可能存在向上延伸的路径)。在保证合法的前提下,向上延伸的路径应该尽量长,因此可以将\(x\)个儿子的路径长度排序后,二分求出最长的可向上延伸的路径(保证其余路径可以实现合法匹配即可)。根节点不存在可向上延伸的路径,可能需要一些特判。

总时间复杂度\(O(n\log^2n)\)

code

「USACO 2020.2 Platinum」Equilateral Triangles

把坐标系旋转\(\frac{\pi}{4}\),曼哈顿距离就变成了切比雪夫距离,点\((x_1,y_1)\)\((x_2,y_2)\)的距离为\(\max\{|x_1-x_2|,|y_1,y_2|\}\)

简单讨论后可以发现定义在切比雪夫距离下的等边三角形存在两个顶点横坐标相同或纵坐标相同。

枚举横坐标相同的两点\(P(a,b),Q(a,c)(b<c)\),可与之构成切比雪夫距离等边三角形的第三点坐标集合为\(\{(x,y)|x=a \pm (c-b),b \le y\le c\}\)

两点纵坐标相同的情况类似。为避免重复统计,需要强制不存在两点横坐标不同,也即枚举了两点\(P(b,a),Q(c,a)(b<c)\)后,统计的集合为\(\{(x,y)|b<x<c,y=a\pm (c-b)\}\)

预处理每个横纵坐标顶点数的前缀和即可。复杂度\(O(n^3)\)

code

「USACO 2020.2 Platinum」Help Yourself

众所周知\(n^k=k![x^k]e^{nx}\)

我们可以认为,若一种方案的联通块个数为\(n\),那么其生成函数就是\(e^{nx}\)

对于给出的区间按左端点升序排序依次加入,记\(dp[i]\)表示以\(i\)作为当前最右端点的区间集合的对应的生成函数之和。考虑新加入一个区间\([l,r]\)时,\(dp\)数组的变化情况。

  • \(i<l\),那么在\(dp[i]\)后面接上新区间\([l,r]\)会使得联通块数增加\(1\),因此转移可以写成\(dp[r] \gets (\sum_{i<l}dp[i])e^x\)
  • \(i \in [l,r]\),那么联通块数不变,而右端点会变为\(r\),即\(dp[r] \gets (\sum_{l \le i \le r}dp[i])\)
  • \(i>r\),加入\([l,r]\)后完全没有影响(区间按照左端点顺序加入,\(i>r\)说明此前存在一个满足\(l'<l,r'>r\)的区间\([l',r']\),因此\([l,r]\)被完全覆盖了),直接令\(dp[i] \gets dp[i] \times 2 (i>r)\)即可。

使用线段树实现上述操作,由于一次幂级数乘法的时间复杂度为\(O(k^2)\),因此算法的总时间复杂度为\(O(nk(k+\log n))\)

code

posted @ 2019-12-23 10:16  租酥雨  阅读(2540)  评论(36编辑  收藏