题解 loj3265 3266 3267 USACO 2020.2 Platinum(全)

loj3265 「USACO 2020.2 Platinum」Delegation

因为是最大化最小值,考虑二分答案。

设当前二分的答案为\(K\)。则要判断是否有一种划分方式,使得每条链的长度都至少为\(K\)

不妨以\(1\)为根,对整棵树dfs。记\(fa(u)\)\(u\)的父亲节点。dfs(u)函数求出一个值\(f(u)\),或判断在当前的\(K\)下无解。有解时,我们把\(u\)的子树划分为若干条长度\(\geq K\)的链,并选择一条未完结的链(允许这条链长度\(<K\))覆盖\(u\)\(fa(u)\)之间这条边。这条链会被交给dfs(fa(u))继续处理。而\(f(u)\),就是这条返回给\(fa(u)\)的链的最长长度。dfs(u)函数要做的,就是在保证其他每条链长度都\(\geq K\)的前提下,让\(f(u)\)的长度尽可能大。

考虑dfs(u)函数的实现。先递归\(u\)的所有儿子,每个儿子\(v\)会带来一条长度为\(f(v)+1\)的链(这个\(+1\)就是\(u,v\)之间的边,它没有被算在\(f(v)\)中)。把得到的这些链按长度排序。此时我们有两种选择:

  • 方案一:把所有这些链两两匹配。(如果链的数量是奇数,就加一条长度为\(0\)的链)。要求每对匹配链的长度和\(\geq K\)。并令\(f(u)=0\)
  • 方案二:挑出一条链作为\(f(u)\),让其余的链两两匹配。如果能匹配成功,则令\(f(u)=\)这条挑出来的链的长度。

这里的“两两匹配”,我们可以做一个简单的贪心:让最大的链和最小的链匹配,第\(2\)大的链和第\(2\)小的链匹配......。如果存在某一对链的长度和\(<K\),说明匹配失败,无法找到合法的匹配方案。

\(u=1\)时,我们显然只能选择方案一,即把所有链都匹配起来。否则无解。

\(u\neq 1\)时,本着让\(f(u)\)尽可能大的原则,我们优先考虑方案二。如果无法实现方案二,再考虑方案一是否可行。若也不可行,则无解。

现在的问题是,如果选择方案二,我们该如何在保证其它链能够成功匹配的前提下,挑出一条尽可能长的链作为\(f(u)\)呢?考虑两条长度分别为\(x,y\)的链,若\(x<y\),则若挑出\(y\)这条链后其它链能够成功匹配,挑出\(x\)后其他链也一定能成功匹配(这相当于把匹配中的\(x\)换成\(y\),有一条链变得更长了,匹配结果不会变差)。故可以二分把那条链作为\(f(u)\),判断是否可行即可。

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

参考代码

loj3266 「USACO 2020.2 Platinum」Equilateral Triangles

图片来源:洛谷用户:ix35

观察一个曼哈顿等边三角形:

红线、蓝线分别是\(BC,AC\)的曼哈顿距离。

把线段平移,得到下图:

此时,\(BC\)的曼哈顿距离是\(\color{red}{\text{红}}\)\(+\)\(\color{green}{\text{绿}}\)\(AC\)\(\color{blue}{\text{蓝}}\)\(+\)\(\color{green}{\text{绿}}\),于是我们可以得到:\(\color{red}{\text{红}}\)\(+\)\(\color{green}{\text{绿}}\)\(=\)\(\color{blue}{\text{蓝}}\)\(+\)\(\color{green}{\text{绿}}\),所以\(\color{red}{\text{红}}\)\(=\)\(\color{blue}{\text{蓝}}\)。同理可知:\(AO=BO=CO\)(曼哈顿距离)。也就是说,\(O\)\(\Delta ABC\)在曼哈顿距离意义上的“外心”。

考虑枚举这个外心\(O\),再枚举\(O\)\(A,B\)的距离\(r\)。大力讨论\(A,B\)所在的象限(四种情况)。此时\(A,B\)的位置就已经确定了。考虑\(C\)。首先\(C\)一定在和\(A,B\)相反的象限,且\(OC=r\)。可以发现这样的\(C\)一定在一条斜\(45^{\circ}\)角的线上(即平行于矩形某条对角线的线)。对每条这样的斜线做前缀和即可\(O(1)\)查询出\(C\)的数量。

时间复杂度\(O(n^3)\)

参考代码

loj3267 「USACO 2020.2 Platinum」Help Yourself

把所有线段按左端点排序。设\(dp_0[i][r]\)表示考虑了前\(i\)条线段,最大右端点在\(r\)时,有多少满足条件的线段子集;\(dp_1[i][r]\)表示此时所有满足条件的线段子集,每个线段子集的的连通块数之和;\(dp_2[i][r]\)表示此时所有满足条件的线段子集,每个线段子集的的连通块数的平方,之和......。

一般地,定义\(dp_k[i][r]\)表示考虑了前\(i\)条线段,最大右端点在\(r\)时,所有满足条件的线段子集,每个线段子集的并的连通块数的\(k\)次方之和(\(0\leq k\leq K\))。设对于一个线段集合\(s\)\(\operatorname{maxendpos}(s)\)表示\(s\)中所有线段的最大右端点,\(cnt(s)\)表示\(s\)的连通块数。则:
\[ dp_k[i][r]=\sum_{s\in[1,i],\ \operatorname{maxendpos}(s)=r}cnt(s)^k \]
考虑新加入一个线段\(i\)。从\(dp[i-1][j]\)转移到\(dp[i][?]\)。分三种情况讨论:

  • \(j<l_i\),此时加入线段\(i\)会使右端点变为\(r_i\),且连通块数\(+1\)
  • \(l_i\leq j\leq r_i\),此时加入线段\(i\)会使右端点变为\(r_i\),且连通块数不变。
  • \(j>r_i\),此时加入线段\(i\)既不改变右端点也不改变连通块数。

发现问题主要在于连通块数\(+1\)时的转移不好处理。考虑现在有一\(dp_k[i][j]\),把它的连通块数\(+1\),看它的值会如何变化:
\[ trans(dp_k[i][j])=\sum_{s}(cnt(s)+1)^k=\sum_s\sum_{t=0}^{k}{k\choose t}cnt(s)^t=\sum_{t=0}^{k}{k\choose t}dp_t[i][j] \]
由此,此时再考虑\(dp_k[i][?]\)的转移式。初始时,令每个\(dp_k[i][j]=dp_k[i-1][j]\),表示在线段集合中不选线段\(i\)的情况。然后考虑选线段\(i\)的情况:
\[ dp_k[i][r_i]+=\sum_{j=0}^{l_i-1}trans(dp_k[i-1][j])+\sum_{j=l_i}^{r_i}dp_k[i-1][j]\\ dp_k[i][x]+=dp_k[i-1][x]\quad(x>r_i) \]
其中\(trans(dp_k[i-1][j])\)可以\(O(K)\)求。故时间复杂度为\(O(n^2K^2)\)

考虑优化。

首先,\(\sum_jtrans(dp_k[i-1][j])\)就等于\(trans(\sum_jdp_k[i-1][j])\)。因为我们在推\(trans\)时并没有用到\(j\)具体的值,只是用\(i,j\)来表示了一堆“线段的集合”。把这些集合先并起来(作为一个更大的集合),再转移也是一样的。

根据套路,不难想到用线段树去维护所有的\(j\)。线段树上,设一个节点所代表的区间为\([l,r]\)。我们在这个节点上存\(K+1\)个值,分别为:\((\sum_{j=l}^rdp_0[i][j]),(\sum_{j=l}^rdp_1[i][j]),\dots,(\sum_{j=l}^rdp_K[i][j])\)

则从\(i-1\)\(i\)的转移相当于:

  • \(r_i\)这个位置执行线段树单点加操作,让它的值\(+trans(\sum_{j=0}^{l_i-1}dp_k[i-1][j])\)。其中求\((\sum_jdp_k[i-1][j])\)要用到线段树区间求和
  • \(r_i\)这个位置执行线段树单点加操作,让它的值\(+(\sum_{j=l_i}^{r_i}dp_k[i-1][j])\)
  • 对线段树\(r_i+1\sim 2n\)这些位置执行区间乘操作,全部\(\times2\)

注意,区间所有的查询操作要在修改操作之前进行。这样查到的才是\(dp_k[i-1]\)的值。

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

参考代码

猜你喜欢

转载自www.cnblogs.com/dysyn1314/p/12403868.html