Codeforces Global Round 18 A~F 题解

比赛链接

A

容易发现总和不会变。

那么如果总和是 \(n\) 的倍数就输出 \(0\),否则输出 \(1\)

Code:https://paste.ubuntu.com/p/gZZnwtB3VS/

B

对于二进制每一位都记录一下前缀和,删除最少 \(\Lrarr\) 保留最多,对每一位取 \(\max\) 即可。

Code:https://paste.ubuntu.com/p/44pb5QMm5N/

C

模拟几次操作后可以看出,连续两次操作其实就相当于交换原序列的两个数。

那么如果操作偶数次,相当于交换一些 \(01\) 对,最小次数就是 \(a\)\(b\) 不同的位数,当然要保证 \((a_i=0,b_i=1)\)\((a_i=1,b_i=0)\) 的数量一样。

如果操作奇数次,最后一次肯定剩下一个位置 \((a_i=1,b_i=1)\),其他位置全都不同。那么要保证原串中 \((a_i=1,b_i=1)\) 的数量要恰好等于 \((a_i=0,b_i=0)\) 的数量 \(+1\)

Code:https://paste.ubuntu.com/p/YtnHS9rj2T/

D

一个小结论:\(\text{popcount}(x\oplus y)\mod 2=(\text{popcount}(x)\mod2)\oplus(\text{popcount}(y)\mod 2)\)

证明考虑异或的本质是不进位加法,每次只会消掉偶数个 \(1\)

所以每条边的权值都可以换成 \(0/1\)

比较显然的结论:\(u_i\)\(v_i\) 路径上的权值异或和 \(=\) 根到 \(u_i\) 路径上的权值异或和 \(\oplus\) 根到 \(v_i\) 路径上的权值异或和。

\(a_i\) 表示根到 \(i\) 路径上的权值异或和。显然 \(a_i\in\{0,1\}\)

那么给出若干个限制其实就是说 \(a_{u_i}\oplus a_{v_i}=0/1\),每条已给定边权的边同样给出了一个限制。

不难想到 可以用扩展域并查集做。每个点开两个节点 \(b_{i,0/1}\),如果有一个限制就将对应的节点所在集合合并。无解的情况就是有限制不能满足或者 \(b_{i,0}\)\(b_{i,1}\) 在同一个集合里。

实现的时候可以强制将小的点向大的点合并,这样求出 \(a_i\) 的时候就可以知道 \(i\)\(root\) 是否选的是同一个数。肯定有一堆其他写法,毕竟这是扩展域并查集板子……

Code:https://paste.ubuntu.com/p/D5V2KXCFGC/

E

发现三个变量不好整,于是把 \(w\) 换成 \(n-r-b\),原式变为 \((n-r-b)(r-b)=r(n-r)-b(n-b)\)

那么第二个人肯定会最大化 \(b(n-b)\),这是一个关于 \(b\) 的二次函数,在 \(b=\frac{n}{2}\) 的时候最大。

不难发现如果第二个人能选 \(x\) 个点,那么肯定能选 \(x-1\) 个点。把选择的子树的根去掉,把它所有儿子的子树都选掉即可。因此第二个人会选的节点一定是 \(\min(\frac{n}{2},y)\),其中 \(y\) 是第二个人能选择的染蓝的最大节点数。所以第一个人的目的肯定就是最小化第二个人选的染蓝的节点数。如果有所保留,那么第二个人选掉就肯定不优。

考虑第一个人操作的实质,其实就是把一个点到根的路径上的所有点设成第二个人不能选。

不难发现选叶子节点一定比选它的祖先更优。那么问题就变成选一些叶子节点,使它们到根的路径的并的大小最大。这个可以长链剖分后贪心做。

Code:https://paste.ubuntu.com/p/WnnhM2NjZY/

F

也是一道神仙题。

看到两个相邻的 \(0/1\) 不好处理,于是考虑一个套路:将所有奇数位上的 \(0\to1\)\(1\to0\),这样每次操作也就是交换相邻的两个 \(01/10\)

首先有解的充要条件就是 \(s\)\(t\) 在转化后 \(1\) 的数量相同。

实际上,\(s\)\(t\) 的距离就是 \(\sum\limits_i\) 两个串中第 \(i\)\(1\) 的位置差。这样还是不好计数,考虑转化一下:设 \(x_i=\sum\limits_{j=1}^i[s_j=1]\)\(y_i=\sum\limits_{j=1}^i[t_j=1]\),那么 \(s\)\(t\) 的距离就是 \(\sum\limits_{i=1}^n|x_i-y_i|\)。意思就是说每一个 \(s\) 中的第 \(i\)\(1\)\(t\) 中第 \(i\)\(1\) 的贡献是二者的位置差。

这种方法成功将每一位的贡献拆开,那么根据这个就可以 DP 了。设 \(pre_{i,j}\) 表示考虑到前 \(i\) 位,\(x_i-y_i=i\) 的方案数,\(suf_{i,j}\) 表示考虑后 \(i\) 位,后 \(i\) 位中 \(s\)\(1\) 的数量与 \(t\)\(1\) 的数量的差。

转移的时候枚举这一位填 \(1/0\),最终答案就是 \(\sum\limits_{i=1}^n\sum\limits_{j=-n}^n pre_{i,j}\times suf_{i,-j}\times|j|\)

Code:https://paste.ubuntu.com/p/WrbFFZyCR2/

posted @ 2022-03-04 14:57  csxsi  阅读(49)  评论(0编辑  收藏  举报