A - Axis of Symmetry
一道非常有趣的题目。感觉官方题解不太详细啊……很多东西都没有点出来。
首先有一个结论:答案最多只有 (4):水平竖直及两条斜率分别为 (pm 1) 的直线。具体可以算出横纵坐标的最大最小值得到。
不过官方题解的思路是富有启发性的:考虑如果矩形间全部不相邻,那么直接判所有的矩形边界线段即可。然而由于存在两个小矩形合并为大矩形的情况,直接操作会误判。然后我们需要进行一些操作:将相接的线段合并,以及删去两个矩形的公用边。
但我们可以不这么实现,因为细节不清不楚而且比较复杂。我们判线段,本质上在判线段上的点。能不能直接判点集的对称性呢?
对于干扰点,其可能的情况为:在(组合)矩形的边上,或被四个矩形包夹。这些点不能表现图案,但会使我们误判。观察得知,成为这种点有一个充要条件,就是作为矩形的角出现偶数次!
也就是说,我们筛去这些点,剩下的点就能反映图案的所有“拐角”,也就表现了图案。其实筛掉这些点,实际上和官方题解提到的方法本质相同。
最后判对称的话,这么做都可以了。复杂度 (O(nlog n))。
B - Binary Tree
噗 什么演王题
考虑到每次取走的子树大小必然为奇数。
所以判断 (n) 的奇偶性即可。
C - Constructing Ranches
首先考虑一列数 (a_{1sim n}) 可以构成简单多边形的一个简洁的充要条件:(2cdot max_i a_i <sum_i a_i)。
然后大致的做法就比较清楚了,点分治统计合法路径数。
对于两条路径,其路径最大值分别为 (x_1, x_2),路径和分别为 (y_1,y_2)。那么简单推导,产生贡献的条件有:(egin{cases} x_2<x_1 \ y_2 > 2x_1-y_1 end{cases})(其中 (x_2<x_1) 可以确定最大值)。
很显然是一个二维偏序问题,使用容斥统计可以变成静态问题,扫描线树状数组可以解决。算上分治时间复杂度 (O(nlog ^2 n))。
一个细节就是,然后处理两条路径对接时分治中心的影响(单独说一下是因为没想清楚被卡了好久)。第一种方法是一开始不处理根,在后期统计时加上,但这样会影响最大值以及和两个指标,非常麻烦。而另一种方法是一开始就加上,这样后期就只要在和上减掉重复统计的中心即可,而最大值则不用管,会方便不少。
D - Defining Labels
找规律。对于一个 (10- extit{based}) 编号 (X_kX_{k-1}cdots X_1X_0),其对应的十进制真实值为 (sum_{i=0}^k (X_i +1) imes 10^i)。
类比到 (k- extit{based}) 编号,只要做正常的进制转换,只是进入递归前将 (X) 减一,并加上 (10-k) 即可。
E - Erasing Numbers
又是神奇结论题。又是我不会的题。
首先发现 (nle 5000),大概推测解法是对每个数都做一次 (O(n)) 的判断。那么对于每个数 (x) 做判断时,可以发现我们在考虑其他数时,可以只考虑其与当前数 (x) 的大小关系。于是小于的记为 (0),大于为 (1)。
然后有一个结论:如果序列中 (0) 的数量和 (1) 相等,那么一定可以消到只剩下 (x)。可以发现,如果两者分别都在 (x) 两侧的各一侧,那么一定可以操作 0x1
或 1x0
直到剩下 (x)。如果是混杂的,那一定可以找到一个位置 (0,1) 相邻,然后使两者的数目各减去一。
当然不可能都是相等的,那么考虑将多出来的那个消去一些。注意到如果要消掉多余的 (0),那么只有 000
的情况是靠谱的。如果没有连着的,我们可以消去中间将其隔开的 01
达到目的。
于是有了这样的算法:扫过去,每当出现一个子段 (0) 比 (1) 多三个,就可以直接减掉两个 (0)。(x) 两侧各执行一次即可,直到数量相等则判断成功。
复杂度 (O(n^2)),感觉不是那么简单的题,为啥过了这么多啊。
G - Game Design
简单构造。首先根比较有用我们使其点权为 (10^9),让其对解数无影响。
考虑这个 (K) 实际必然是若干个数乘起来的结果,于是考虑在根上挂上若干条链,每条长度(点数)为 (l) 的链,我们令链上的点权为 (1),那么就是 (l) 种方案。
于是不难想到质因数分解:(K=prod_i^k p_i^{c_i})。那么乘上一个 (p),就在根上挂一条 (p) 个点的链。
注意到我们有点数限制,而质因数分解就是为了把乘法变成加法使得点数为 (sum_i^k c_ip_i) 规模。但如果 (K) 中存在一个巨大无比的质因子——或者说就是大质数(如 (998244353)),那点数还是太多。
考虑微操一下:我们尝试将 (K) 减一。可以发现这样其分解会有很大的变化,常数轮之后就没有过大的质因子了。得到处理过的 (K' = K- t) 后,对应的,在根下建 (t) 一个新点,那几条链连在这个新点而不是根上,新点的权值为链的数目。注意这时这些链由 (K') 导出。很显然这时点数还是 (O(log K)sim O(log ^2 K)) 左右,可以通过。
H - Hold the Line
单点加入(从无到有),区间查询前驱后继。在线的话,一看就是要维护动态的二维信息,那么一个线段树套 set 的大常数 (log ^2) 做法是显然的。然而 (nle 5cdot 10^5) 这么大的数据肯定过不了,但由于这动态的二维信息摆在哪里,正解应该是离线小常数的 (O(nlog ^2 n))。
扫描线。我们固定右端点 (R),这时 (le R) 的插入操作就已更新。考虑维护用一个以权值为下标的线段树,我们要求前驱或后继,可以直接在线段树上二分求解。每个线段树结点保存的是二维点集 ((t,p)):插入时间 (t) 以及位置 (p)。
于是,判断一个线段树结点是否包含可行点,只要查询每个点左上区域是否存在点即可。然后就是一个 trick:若存在 (A,B) 两点满足 (A) 在 (B) 的左上方,那么 (B) 就完全没用了。删去所有这样的 (B),余下的点按 (t) 排序,(p) 也是单调的。这样就变成一维问题了!判断存在只要在单调点列上二分查找即可。
然而我们要支持动态插入,好像又要用 set 了!但注意到,我们有一维是位置,而推进扫描线使得加入的点在位置上就是天然单调的,仔细一想其实只要 vector 就行了。
最后复杂度是 (O(nlog ^2n))。
I - Incoming Asteroids
跟着这题学了个新 trick /se
考虑每个任务的 (k) 都很小,那么对这 (k) 个位置都设一个 (lfloor y/k floor) 的阈值。每当 (k) 个位置的其中一个达到了这个阈值就重构这个任务并重新放置。(要说这怎么想到的……只能说 (k) 个位置都地位相等,自然阈值都相等;而要保证所设的阈值不能出现“完成了却不知道”,最大的可行阈值就是 (lfloor y/k floor))。
复杂度不难证明,由于一次重构意味着减小 (1/k),那么复杂度就是 (O(nlog nlog y))。其中 (log n) 是维护需要的数据结构的时间。
J - Junior Mathematician
摆明了是数位 dp。复习一下。
考虑我们记搜时要记录那些信息到状态里面:位数,是否有上界(基础信息,这里似乎不需要判前导零),(xmod m),(f(x)mod m) 以及数位和。
但是这样维度有点多,冷静分析可以发现 (xmod m,f(x)mod m) 这两个我们可以用一个 (f(x)-x mod m) 代替。
然后在转移注意下细节和卡常就好啦。写了个小丑 map 被卡爆了
K - Key Project
我网络流水平菜到离谱了哇
这题的费用流还是很明显的。建模:对每栋楼建点,对于一个 algorithm engineer((A))我们从原点 (S) 向其所在建筑连容量为 (1),花费为 (c_i) 的边;对于一个 software engineer((B))我们从其所在建筑向汇点 (T) 连边。
传统的 EK 费用流算法,复杂度为 (O(mcdot mlog n)/O(mcdot nm)),无法通过。考虑到这个算法慢在寻找最短路,而显然这张图是有特殊性质的,考虑优化最短路的寻找过程。
首先观察得知,对于所有 (S o i) 的边,我们只保留(之前没用过的)花费最小的那条。对于 (i o T) 的边同理。而且和源汇点连接的边不需要退流(即不需要反边)。
所以我们主要考虑的只有中间那 (n) 个点。相邻点之间有两个方向的边(方向不同,边权也不同还可能为负)。
接下来就能用线性的扫描代替最短路了。不是一般性设最终选取的组合 (A) 在 (B) 左侧,维护左侧到当前位置的最短距离即可。反过来做一次就能处理 (A) 在 (B) 右侧了。找到后记得更新边上的花费。
很显然一次扫描 (O(n)),总复杂度 (O(nm))。有点像模拟费用流? 一开始还在想用费用流证凸性然后胡乱凸包
代码还没有写完 写完了,就你卡常数是吧