ASC11

上来先开了 D,比较简单的小题

D - Integer Numbers

题意:现在有一个序列,改变最少的位置,使得这个序列是等差数列,输出方案。
我们发现,如果我们不改变 \(a_i\),那么只有满足 \(a_i-a_j=i-j\)\(j\) 是不需要改变的。也就是需要改变的数是 \(n\) 减去 \(a_i-a_j=i-j\) 的个数(\(i\) 可以等于 \(j\))。而 \(a_i-a_j=i-j\) 也就是 \(a_i-i=a_j-j\),我们先用一个 map 存好,然后直接在 map 里查找即可。很多人用了两个 map,是多此一举的。

然后就来到了 E,不是很难,但是卡了我很久,暴露了我在编码上的短缺,省选D2T1挂掉也有编码的一部分原因。

E - Islands

题意:一个六边形坐标系,每次转变一个位置为陆地,如果当前的操作会导致出现大小大于 \(s\) 的陆地连通块,就忽略这次操作。最后输出所有的连通块大小。
我们可以先编码然后使用维护 size 的并查集,每次对于当前的点,先找到相邻的六个点所属的集合,如果它们的 size 之和(注意同一集合的不能重复计算)大于 \(s-1\),就忽略操作,否则直接将当前点和周围的点 merge 起来更新 size
E 的一部分难度在实现,首先是找邻居,奇数点和偶数点找邻居的方式不一样,需要分开处理。其次就是编码,虽然我们的值域是 \([-500,500]\),但是在找邻居的过程中就可能出现 \([-501,501]\),这样我们就需要加上 \(501\),并且之后的值域变成 \([0,1002]\)。为了并查集没有 \(0\),还要给编好的码加一,就是这些小细节卡了我 11 发罚时,是很恐怖的。

E 之后就是大诈骗 C,第一眼没有看到必须沿着格线,以为是任意多边形,就浪费了一段时间。然后想好了扫描线,但是又觉得这么快过了 20 多个人的题不应当这么难,就继续想,但最终还是写了扫描线。

C - Black and White

题意:对于一个直角坐标系,按逆时针顺序给出一个多边形,保证顶点都是格点且都沿着格线。给坐标系的 \(1\times 1\) 方格黑白染色,\((0,0)\) 处是黑色,其他相邻格子染色不相同,求多边形包含的黑格子和白格子个数。
扫描线:虽然不是正解,但是写这个的冤种比写正解的多得多。比较常规的扫描线,唯一的问题就是它给出的是格线。不过我们发现因为是逆时针,所以可以通过格线往上还是往下判断格线的左边在型内还是右边在型内。然后就是常规的扫描线,每次插入需要的操作,对当前所有的相邻格线进行配对,在线段树上维护当前加入的列中奇数的个数和偶数的个数。然后对线段树和 map 硬操作就行了。细节巨大量多,从合并格线、线段树和最后统计答案全都是细节,但是奇迹般的没有挂很多。
前缀和容斥:妙啊,很妙啊!我们先把所有的格点转移到正半轴,然后对于每个格点直接统计它和原点构成的矩形之间的黑格子和白格子个数。统计答案的时候隔一个逆转一次符号加入进去,就可以了。我们仔细想一想,会发现这是对的,因为每个格子恰好会被奇数个格点的矩形覆盖,而且如果给格点二染色,所有的格子能遇到的格点段都是相同颜色开头结尾的。

码过了 C 之后,犹豫了一下开了 H,还是比较明显的 dp 啊。

H - Saving Princess

题意比较复杂,这里不太能描述清楚。
但实际上,我们可以直接照着模拟。设 \(dp_{i,s,p,m}\) 为当前走到第 \(i\) 只怪兽,主人公的能力值是 \(s,p,m\) 的最大的 \(health\)。然后照着他说的模拟就可以了。每次打怪兽还是躲过去,两种情况对指标的影响反映到状态上。但是这样写是存在一些问题的。第一,我们 \(s,p\) 是可以增长的,最多增加 \(n\),这样状态增加了 \(4\) 倍,不太划算,我们可以把 \(s\)\(p\) 设置成当前值和初始值的差,这样状态就重新变成了 \(50^4\)。第二,空间是卡的。但是我们发现,即使暴力回溯,即每次都记录 \(s,p,m\) 回溯,任何的值都不会超过 \(50\),所以直接用 char 代替 int 解决卡空间的问题。第三,回溯是可以优化的。我们只需要记录上一次是打怪还是躲过去就可以了。因为唯一不好倒推的指标是 \(h\),但 \(h\) 在状态里面,不是状态的下标。所以又可以优化很多的空间和很多的常数。复杂度一直是 \(O(n^4)\)

H 并花不了太长时间,很快就来到了 I。

I - Radio Waves

题意:对于二维平面上若干个基站,需要设置一个最大的 \(k\),使得我们可以把基站划分成两个集合,相同集合内的基站为圆心 \(k\) 为半径画圆互不重合。
二分法:考虑二分答案,然后互相画圆会重合的点之间连边。我们要找到两个集合互相不重合,其实就是要找二分图。可以直接二分图染色判定。最后输出染色方案。因为边数是 \(n^2\),所以复杂度是 \(O(n^2\log w)\)
扩展域并查集法:我们可以把所有点对之间连边所最小需要的 \(k\) 排序,然后从小到大枚举加边,用扩展域并查集动态判断加入当前边之后的图是二分图,这是经典操作,扩展域并查集就是干这个的。复杂度 \(O(n^2\log n^2)\),并查集优化没用,因为前面还有排序瓶颈在。

I 的扩展域并查集还是很妙的,但是二分也不比它差很多就是了。之后就是 F。

F - Counterfeit Money

题意:给出两个矩阵,求最大公共子阵。
出题人的本意似乎是哈希?但是哈希完全没必要且被薄纱。我们可以先对于所有的 \((i,j)\)\((x,y)\) 枚举出两个矩阵中,从位置 \((i,j)\)\((x,y)\) 往下延伸,最多延伸长度多少能使得延伸的部分是相同的。这一过程是 \(O(n^5)\)。然后直接枚举两个矩阵的左上角。然后一直往右延伸。我们发现矩阵的高度不能超过从这一行的任意一对位置往下最大延申长度的最小值。那么我们就可以一直往右延伸并动态记录之前求出来的东西的最小值,然后用当前往右延伸长度和往下延伸长度作为子矩阵的长和宽直接作为答案就可以了。总复杂度 \(O(n^4)\)

F 过了之后去开 A,第一眼:这不是费用流板子吗?然后:挂样例。

A - Beer Problem

题意:给出一个无向网络,求其最大费用流(不是最大费用最大流)
首先考虑无向图怎么解决。先尝试对每个边构造一个子结构,具体方法是对每个边 \((x,y)\) 新增两个点 \(a,b\),然后从 \((x,y)\) 分别向 \(a\) 连有向边,\(b\)\((x,y)\) 连有向边。\(a\)\(b\) 之间连流量为 \(f\),费用为 \(c\) 的边。这样就和无向边是一样的。但是这会让我们的点数变成 \(O(m)\) 的。我们发现一条边其实不可能从两边都流哪怕一个流量。因为我们把两边的流量互换,因为边权是负的,所以两边都不流这个流量一定是更优的。所以我们可以直接两边连流量费用 \((f,c)\) 的有向边。但是只有最大费用流且边权是负(或最小费用流边权是正)的时候可以这么干。然后考虑解决最大费用流。首先众所周知费用是关于流量的凸函数,那么我们就可以限制从源点出发的流量,然后三分法找到费用函数的顶点。可惜这样复杂度是寄的。然后我们试着残量网络优化,每次给源点加一的流量,然后就在残量网络跑一遍 MCMF,但是这样相当于把费用流那个很松的 \(f\) 给卡满了,复杂度就是满的 \(O(nmf)\),也是会挂的。我们考虑从网络流本身入手。我们费用流的算法,实际上是每次沿着最短路/最长路去流,每次的贡献就是最短路/最长路的长度。最小费用最大流是每次沿着最短路找。那么实际上,只要我们的最短路 \(>0\),因为 Dinic 的性质使得最短路不会减少,所以再往后的路径就一定是正的贡献,就干脆不流了。也就是只要 spfa 返回的 \(dis_t\) 是正的就直接结束费用流算法。这样就可以求出最小费用流了。

A 是直到赛后才过的,但是这个题也是给我启示最多的,包括无向边建法、费用流凸函数以及 MCF 的算法。但是赛时卡 A 了之后,我的最后 30min 都花在了 K 上,K也不负我的期望,在赛后才过掉。

K - Gone Swimming

题意比较复杂,不太写的清楚
我们考虑暴力模拟,首先记录每对 section 之间的公共边长度,然后每次对当前的状态,求出所有没有被灌满的泳池每分钟增加的水量,公式是 \(flow_j=s\dfrac{curlen_j}{totlen}\),其中 \(curlen_j\) 是当前 section 和已经灌满部分的公共边长度,\(totlen\) 是当前已灌满部分的总周长。我们查找当前状态下,哪个水池会最先灌满。找到这个时间,把每个水池在这段时间加上的体积加上。对于新灌满的水池,更新所有的 \(curlen\)\(totlen\),更新这个是简单的。然后继续计算直到所有的水池都被灌满。在刚开始做的时候,我把 the number of the section where the water source is located 当成了“有源头的水池的数量”而误以为可能有多个源头,是不可做的,实际上等我转念一想,它这样不就没有说明白每个水池源头的数量吗?然后对着样例发现 number 是“编号”不是“数量”,这样这道题就好做了。

posted @ 2023-05-26 21:42  jucason_xu  阅读(14)  评论(0编辑  收藏  举报