EDU124

C. Fault-tolerant Network
题目大意
一间教室里有两排电脑,每排有 nn 台,每台电脑有自己的一个等级。
第一排的电脑等级依次为a1,a2,,ana_1, a_2, \cdots, a_n ,第二排的电脑等级依次为 b1,b2,,bnb_1,b_2, \cdots, b_n

起初,对于每一排电脑,所有相邻的电脑之间有网线连接。因此两排电脑是相互独立的两套计算机网络。
你的任务是把两排电脑连接到同一个计算机网络中,你可以在两排电脑之间连接一或多对计算机。
将第一排的第 ii 台电脑和第二排的第 jj 台电脑相连需要花费 aibj|a_i - b_j| 的代价

你可以把一台电脑与另一排的多台电脑相连,但是你联通的网络需要满足最基本的容错性:
不管哪台电脑坏掉,这个网络的剩余部分都不会断开(即其他计算机仍可以两两互通)。

你需要最小化代价。

思路分析
画一下图,可以发现 {a1,an}\{a_1, a_n\} 一定要有到 bb 的链接,同时 {b1,bn}\{b_1, b_n\} 也要有到 aa 的链接
可以用反证法证明
不妨设 aia_i 坏掉了,如果 ana_n 没有到 bb 的链接的话,那么 (ai+1,,an)(a_{i+1}, \cdots, a_n) 这些电脑是链接不到 bb
bb 也同理

所以就依次考虑 (a1,an)(a_1, a_n)(b1,bn)(b_1, b_n),对于 (a1,an)(a_1, a_n),枚举 bb 中哪个点距离它最近
(b1,bn)(b_1, b_n) 同理,这样就保证了 a1,an,b1,bna_1, a_n, b_1, b_n 四条线都被连上了,一定是一组合法的解

值得注意的是,(a1,b1),(an,bn),(a1,bn),(an,b1)(a_1, b_1), (a_n, b_n), (a_1, b_n), (a_n, b_1) 彼此相连的情况
并不需要 44 条线

下面来讨论一下

  • (an,bn)(a_n, b_n) 连,此时若 bib_i 坏了,对于 bi1b_{i-1} 要想连到 bi+1b_{i+1},需要
    bi1b1ajanbnbi+1b_{i-1} \to \textcolor{red}{b_1 \to a_{j} } \to a_{n} \to b_{n} \to b_{i+1},此时对于 b1b_1 找到最小的 aja_j 即可
    同理,aia_i 坏了,ai1a_{i-1} 要通过 a1a_1 才能连通到 bb,此时需要找到最小的 (a1bj)\textcolor{red}{(a_1 \to b_j)}
  • (a1,b1)(a_1, b_1) 连,同理,连最小的 anbj\textcolor{red}{a_n \to b_j}bnaj\textcolor{red}{b_n \to a_j}
  • (a1,bn)(a_1, b_n) 连,连最小的 anbj\textcolor{red}{a_n \to b_j},和 b1aj\textcolor{red}{b_1 \to a_j}
  • (an,b1)(a_n, b_1) 连,连最小的 a1bj\textcolor{red}{a_1 \to b_j}bnaj\textcolor{red}{b_n \to a_j}

CF778(div1+div2)

C. Alice and the Cake
题目大意,给你一块蛋糕,切 n1n-1 次,每一次选 w2w\geqslant 2 的块,切成两部分

分别是 w2\displaystyle \left\lfloor \frac{w}{2} \right\rfloorw2\displaystyle \left\lceil \frac{w}{2} \right\rceil,这样得到一个序列 aa
现在给你一个序列 aa,问你这个序列能不能拼接成完整的蛋糕,能输出yes,否则输出no

算法分析

这种问题一般有两种考虑,第一种是由序列倒着来拼,还有一种就是枚举初始蛋糕到底是那一块

先尝试倒着来拼接,(x1,x2)(x_1, x_2) 拼接,那么 x1=(w1),x2=((w1)1)+1x_1 = (w \gg 1), \quad x_2 = ((w-1) \gg 1) + 1

右移运算还原成 ww 比较麻烦,所以考虑其他做法

注意到 w2+w2=w\displaystyle \left\lfloor \frac{w}{2} \right \rfloor + \left \lceil \frac{w}{2} \right \rceil = w,所以切割过程,蛋糕质量不会凭空消失

由此蛋糕的总质量一定是 S=aiS = \sum a_i

这样就可以考虑对蛋糕进行切割了,贪心地做,因为蛋糕只会越切越小
所以用两个堆维护当前蛋糕的最大块,和当前待匹配的序列的最大值
如果当前蛋糕最大块都小于序列最大值,那么怎么样都不可能匹配上了,直接返回错误
如果最大块和序列最大值相等,记一次匹配,同时弹出最大块和最大值
如果最大块更大,那么把最大块切成两部分,并且弹出原来的最大块
模拟这个过程,如果最后序列都匹配上的话,那么就是合法的

总结
这是一个 max1max2\max1 \geq \max2 的问题,这类问题要想到用两个堆去维护

CF747(div2)

C. Make Them Equal

题目大意就是说,给你一个字符 c\text{c},和一个长度为 nn 的串
你必须把串所有数都改成 c\text{c},问最少操作几次
修改的要求是,每一次你都可以任意选择一个 1xn1 \leqslant x \leqslant n 的数
一次修改,可以把下标不能被 xx 整除位置的数都改成 cc

算法分析
不难发现最多修改 22 次就可以,因为你可以选择 nn,这样把 [1,n1][1, n-1] 位置都变成 cc
然后对于 nn 这个位置,你选择 x=n1x = n-1,把 nn 这个位置也变成 cc

考虑能不能一次完成,那么首先标记待修改的位置 visvis
枚举 xx,同时枚举 xx 的所有倍数,如果发现一个倍数在 visvis 中,xx 就不可以选了
否则就可以选出 xx,一次完成

D. The Number of Imposters

题目大意就是说,nn 个人,每个人可能是诚实的或者是说谎的
给你 mm 个条件,(i,j,c)(i, j, c) 表示 iijj 是一个 cc 类型的人
c=1c = 1 表示 ii 这个人诚实,c=0c = 0 表示 jj 这个人不诚实
问最多的老实人个数

扩展域并查集

  • iijj 是老实人
    • ii 如果老实,jj 也老实
    • ii 如果不老实,jj 也不老实
  • iijj 不老实
    • ii 如果老实,jj 不老实
    • ii 不老实,jj 是老实人

这可以用扩展域并查集来求解,并查集初始化成 [1,2n][1, 2n],对于某个人 i[1,n]i\in [1, n] 而言
编号 i[1,n]i \in [1, n] 表示这个人是老实人,编号 (i+1)[n+1,2n](i+1) \in [n+1, 2n] 表示这个人不是老实人

简而言之,iijj 老实,那么 i,ji, j 属于一个集合
否则的话,iijj 分属两个不同的集合

那么最后一个问题就是如何回答询问
如果一个人 find(x)=find(x+n)\text{find}(x) = \text{find}(x+n),那么矛盾
否则的话 xsz(find(x))\sum_x \text{sz}(\text{find}(x)) 求出老实人集合数,和 xsz(find(x+n))\sum_x \text{sz}(\text{find}(x+n)) 不老实人集合数

然后考虑这两个集合交换一下,取最大值
因为经过上面的分析,我们发现 i,ji, j 的情况用两个集合就可以概括了
与这两个集合哪个是老实人集合,哪个是不老实人集合无关

所以答案实际上就是
max(xsz(find(x+n),xsz(find(x))\displaystyle \max\left(\sum_x \text{sz}(\text{find}(x+n), \sum_x \text{sz}(\text{find}(x) \right)

AtCoder Beginner Contest 254

Together Square

题目大意,给定 nn,求 n\leqslant n 的两个数 (i,j)(i, j),(注:(1,4),(4,1)(1, 4), (4, 1)22 次)
问能找到多少对这样的数对,使得 i×ji \times j 是完全平方数

思路分析
对于 i×j=x×xi \times j = x \times x,考虑 x[1,n]x \in [1, n]
并且尝试从 x×xx \times x 重构出 (i,j)(i, j)

首先对于每一个 x[1,n]x \in [1, n],将其因子分成两部分,分别是
(p1p2pk)×A2(p_1p_2\cdots p_k) \times A^2,其中 A2A^2 表示最大的平方因子
(p1p2pk)(p_1p_2\cdots p_k) 表示不是完全平方的因子

容易发现,从 x×xx \times x 构造 i×ji \times j
(p1p2pk)(p_1p_2\cdots p_k) 这部分是确定的,i,ji, j 都必须包含这部分因子

所以每一个 xx 的方案可以和 v=p1p2pkv = p_1p_2\cdots p_k 方案一一对应
那么我们只需要处理出,对于 xx 而言对应的 vv
并且记一下 vv 能够配上多少给平方因子 c(v)c(v)
当然不配任何平方因子,(i,j)=(v,v)(i, j) = (v, v) 也是一种方案
但这里用了一个技巧,将 11 也看作是一个平方因子,统计到 c(v)c(v)

所以答案就是 vc(v)c(v)\displaystyle \sum_{v} c(v) \cdot c(v)

注意,因为我们是从小到大枚举的,所以对于每一个非平方因子 vv
我们依次检查了 (v×1),(v×22),(v×32),(v×2232)(v\times 1), (v \times 2^2), (v\times 3^2), (v\times 2^23^2)\cdots
不会漏解

Atcoder Beginner Contest 250

E - Prefix Equality

题目大意,给定 A[1n],B[1n]A[1\cdots n], B[1\cdots n] 两个数组,然后有 QQ 个询问
每次询问给你两个数 x,yx, y,问 A[1x],B[1y]A[1\cdots x], B[1\cdots y] 这两个前缀集合中
去重后是否相等

哈希方法
这里用一种哈希的方法来判断,前缀哈希的做法如下

预先遍历数组 AA,对于每个元素 aia_i,将 aia_i 映射成一个随机数,如果映射过了就跳过
具体来说用一个 map\text{map} 记录一下 mp(a[i])=rand()\text{mp}(a[i]) = \text{rand}()

然后用一个 set\text{set} 存放 aia_i,同时计算哈希

1
2
3
4
5
6
7
8
unsigned long long ha[n+1];

for i = 1 to n:
ha[i] = ha[i-1];

如果 a[i] 不在前缀集合中:
ha[i] += mp[a[i]];
将 a[i] 插入集合

计算哈希的关键在于,每一次只在 xx 第一次放入集合的时候计算哈希

Codeforces Round #787 (Div. 3)

E. Replace With the Previous, Minimize

题目大意,给你一个字符串,你可以操作 mm
每一次操作都可以选择一个字母 cc 变成 c1c-1,注意此时字符串中所有的 cc 字母都会变成 c1c-1
你要使得操作完之后字典序最小

思路分析
贪心地看,从前往后,把每一个字符都尽量改成 aa
模拟这个过程,比如 faf \to a,那么一次操作所有的 fef \to e
接下来所有的 ede \to d,以此类推

可以考虑用并查集维护,每一次操作的过程
相当于 (Si)(S_i) 所在的集合和 (Si1)(S_{i} - 1) 所在集合合并

具体到代码实现上,并查集维护集合最小值 minv\text{minv}
比如找到 xx 所在集合的最小值,在并查集中,只需要找到 xx 所在集合的根
r=findpa(x)r = \text{findpa}(x)minv[r]\text{minv}[r] 给出的就是 xx 所在集合的最小值

算法实现如下

  • 从前往后扫描每一个字符 sis_i,修改前它所在集合的根是 r1=find(si)r1 = \text{find}(s_i)
    当前 sis_i 所在集合的最小值 vi=minv[r1]v_i = \text{minv}[r1],令 si=vis_i = v_i
  • 只要发现 m>0m > 0 并且 si>as_i > a,那么就尝试减小 sis_i
    减小后的集合的根应该是 r2=find(si1)r2 = \text{find}(s_i - 1),合并两个集合,即 join(r1,r2)\text{join}(r1, r2)
    一次修改操作完成后,重新确定新集合的根 r=find(a[i])r = \text{find}(a[i])
    更新 a[i]a[i] 为新集合的最小值,即 a[i]=minv[r]a[i] = \text{minv}[r]

二分图匹配

二分图判定

给定一个图是二分图,当且仅当图中不存在长度为奇数的环
判定二分图可以用黑白二染色的方法

关押罪犯

思路分析
本质上是对于任意两个罪犯 (a,b)(a, b),它们的冲突值为 cc,要使得 cc 尽量小

不妨考虑冲突值为 midmid,很显然如果关在一个监狱中的罪犯冲突值都 mid\leqslant mid
那么对于更大的 midmid 仍然是一个可行解

所以考虑二分,不妨设二分值为 midmid,当两个罪犯冲突值大于 midmid 的时候
考虑把这些罪犯单独拿出来,并且连边,构成一张无向图

我们要把无向图分成两个部分,一条边相连的两个点,分属两个不同的集合
实际上,就是如果这个图是一个二分图,那么方案可行,尝试减小 midmid,否则增加 midmid