zoukankan      html  css  js  c++  java
  • 题解 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 eq 1)时,本着让(f(u))尽可能大的原则,我们优先考虑方案二。如果无法实现方案二,再考虑方案一是否可行。若也不可行,则无解。

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

    时间复杂度(O(nlog^2n))

    参考代码

    loj3266 「USACO 2020.2 Platinum」Equilateral Triangles

    图片来源:洛谷用户:ix35

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

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

    把线段平移,得到下图:

    此时,(BC)的曼哈顿距离是(color{red}{ ext{红}})(+)(color{green}{ ext{绿}})(AC)(color{blue}{ ext{蓝}})(+)(color{green}{ ext{绿}}),于是我们可以得到:(color{red}{ ext{红}})(+)(color{green}{ ext{绿}})(=)(color{blue}{ ext{蓝}})(+)(color{green}{ ext{绿}}),所以(color{red}{ ext{红}})(=)(color{blue}{ ext{蓝}})。同理可知:(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)次方之和((0leq kleq K))。设对于一个线段集合(s)(operatorname{maxendpos}(s))表示(s)中所有线段的最大右端点,(cnt(s))表示(s)的连通块数。则:

    [dp_k[i][r]=sum_{sin[1,i], operatorname{maxendpos}(s)=r}cnt(s)^k ]

    考虑新加入一个线段(i)。从(dp[i-1][j])转移到(dp[i][?])。分三种情况讨论:

    • (j<l_i),此时加入线段(i)会使右端点变为(r_i),且连通块数(+1)
    • (l_ileq jleq 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_ssum_{t=0}^{k}{kchoose t}cnt(s)^t=sum_{t=0}^{k}{kchoose 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+1sim 2n)这些位置执行区间乘操作,全部( imes2)

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

    时间复杂度(O(nK^2+nlog nK))

    参考代码

  • 相关阅读:
    第三章 Selenide测试框架
    第二章 自动化测试的本质理解
    第一章 软件自动化测试的基础知识
    【算法学习】03---算法分析学习
    【算法学习】03---算法分析
    【算法学习】02---二分算法总结
    【算法学习】01---java基础以及算法基础常用类库
    前端自动化测试一些学习记录
    Ubuntu下安装Sublime3的Markdown插件
    octopress搭建记录
  • 原文地址:https://www.cnblogs.com/dysyn1314/p/12403868.html
Copyright © 2011-2022 走看看