IPSC 2011 Problem I – Inverting bits

题目链接

IPSC 2011 Problem I – Inverting bits

题目大意

你有 \(26\) 个变量 \(A-Z\),每个变量初始为 \(0\),可以存储一个 \(8\) 位无符号整数,你可以对它们做「 赋值、按位与、按位或、取反、左移、右移、读入、输出」 \(8\) 种操作,运算中可以使用数字常量。

现在你要读入 \(n\)\(0/1\) 值,将它们 flip 之后按序输出,并且不得使用超过 \(k\) 次取反操作。

Easy Subproblem: \(n=7,k=1\)

Hard Subproblem: \(n=19,k=2\)

思路

Easy Subproblem 把 \(7\) 个数字塞到一个变量的前 \(7\) 个二进制位上取反后拆回来输出即可。

Hard Subproblem 相对难一些,有一个直观但延展性差的做法和一个抽象但潜力巨大的做法。

\(n=19\) 很有迷惑性,两个做法都是把它们塞到 \(3\)\(8\) 位整数中然后取反的。

法一

把每个数字看作一个集合,由二进制上为 \(1\) 的位置组成,于是「按位与、按位或和取反」就变成了「取交集、取并集、和全局取补集」的集合操作,把维恩图画出来:

(好像重名了,emmm反正全集用不上不改了)

我们设 \(E\) 为中间三叶草形状的区域:

简洁起见用 \(AB\) 表示 \(A\cap B\)\(A+B\) 表示 \(A\cup B\)\(\overline A\) 表示 \(\complement_U A\),则 \(E=AB+BC+CA\) .

\(E\) 取反,可以发现可以算出 \(X=\overline EA,Y=\overline EB,Z=\overline EC\),利用这个,我们再构造一个图形 \(F\)

\(F=X+Y+Z+ABC\),而 \(\overline F\) 很有用,通过它可以得到 \(U=\overline FAB,V=\overline FBC,W=\overline FCA\),然后我们所需要的信息基本就全了,可以发现原来要求的反即两个扇形(\(X/Y/Z\))和一个三叶草的叶子(\(U/V/W\))以及外面的补集组成,而外面的补集即 \(\overline F\overline E\),所以就做完了:

\(\overline A=\overline E \overline F+Y+Z+W\)\(\overline B=\overline E \overline F+X+Z+V\)\(\overline C=\overline E \overline F+X+U+Y\)

这个做法基本上属于利用了数据小的特点,瞎试出来的,拓展到一般情况很困难,毕竟大小为 \(4\) 的维恩图就已经比较难画了,因此一般情况需要另一个做法。

法二

题解思路,由于把 \(0/1\) 值塞到 \(8\) 位整数里是纯技术问题,下面的 \(n\) 是题面中的 \(\lceil\frac{n}{8}\rceil\)

我们的操作中不包含条件语句,所以需要一种全局性的方法去解决所有情况,注意到二进制的每一位之间是互不干扰的,所以可以分开来考虑,要求我们的做法对于任意一位上的 \(0/1\) 排列都能进行翻转,问题便转化为翻转 \(n\)\(0/1\) 值。

注意到问题的本质就是当一位是 \(1\) 时,将它变为 \(0\),反之变为 \(1\),所以操作需要区分 \(0\)\(1\),那么可以这样区分:假设对于 \(i\in[0,n]\),我们知道 \(ex(i)\) 的真假情况,即 \(n\) 个值中是否恰好有 \(i\)\(1\),,那么当前值 \(a_i\) 翻转后的值可以表示为:

\[Or(\{ex(j)\&Or(\{And(S)|i\notin S,|S|=j\})\}|\;j\in[0,n-1]) \]

其中 \(And(S)\)\(Or(S)\) 分别表示集合 \(S\) 中所有元素的「与和」跟「或和」,若 \(a_i\) 在那若干个 \(1\) 中,则式子为 \(0\),否则为 \(1\) 。于是现在的问题便转化成了如何在 \(2\) 次取反操作内,得到 \(ex(0)\)\(ex(3)\),注意到 \(ex(i)=[one(all)\geq i]\&[one(all)\leq i]\),于是引入 \(lst(i)=[one(all)\geq i],mst(i)=[one(all)\leq i]\),容易发现:

\[lst(i)=Or(\{And(S)|\;|S|=i\}),\;mst(i)= \sim lst(i+1) \]

经过一定的思考便可以得到原题的解法了:

\[ex(3)=a_1\&a_2\&a_3\\ mst(1)=\sim lst(2)\\ ex(1)=lst(1)\&mst(1)\\ ex(1,3)=ex(1)|ex(3)\\ ex(0,2)=\sim ex(1,3)\\ ex(2)=ex(0,2)\&lst(2)\\ ex(0)=ex(0,2)\&mst(1) \]

\(5\) 步的手法很奇妙,我们把它拓展一下,开始我们先用一次取反得到 \(mst(mid)\),可以发现 \([0,mid]\)\([mid+1,n]\) 变成了和原来相同的子问题,注意原来的 \(mst(n)\) 没啥用,它必然为 \(1\),但是在子问题中右端点的 \(mst\) 很有用,并且在求 \(mst(mid)\) 的时候已经得到了。

使用全局分治的思路,在求下一层分治的 \(mst(mid)\) 的时候,我们直接求出所有 \(mid\) 位置 \(mst\) 的或,可以发现即 \(\sim And(\{lst(i+1)|i\in{\text{下一层的mid}}\})\),这个值再与上 \(mst(r)\) 即为 \(mst(mid)\) 了,这样递归总共有 \(\lceil \log_2 (n+1)\rceil\) 层,每层只需要使用一次取反,所以使用这种方法,取反 \(n\) 个数字只需要至多 \(\lceil \log_2 (n+1)\rceil\) 次取反操作即可。

不大会证这是否是下界,但应该也算是比较优秀的做法了吧。

posted @ 2021-09-19 23:34  Neal_lee  阅读(132)  评论(0编辑  收藏  举报