折半搜索
折半搜索
算法原名: \(\text{Meet in the middle}\) ,常译为折半搜索。
适用于输入数据较小,但还没小到能直接使用暴力搜索的情况。
性质
符合折半搜索的题目一般都有经典 \(O(2^n)\) 的暴力且答案符合结合律,便能将搜索序列分为左右各半,去计算左右两边分别能产生的所有答案的序列,然后对左右答案序列进行合并。
比较常见的形式如下:
我们设题面所涉及的运算符为 \(\bigodot\in\{\sum,\prod,\oplus,\land,\bigcup,\bigcap...\}\) 等符合结合律的操作
折半的过程中我们一般为设:
全集 \(Q\subseteq U=\{1,2...n-1,n\}\)
折半 \(Q_l\subseteq U_l,Q_r\subseteq U_r\)
其中 \(\displaystyle U_l=\{1,2,...,\text{mid}\},U_r=\{\text{mid}+1,...,n-1,n\}\)
且 \(U_l\cup U_r=U(U_l\cap U_r=\emptyset)\) ,\(\text{mid}\) 一般取 \(\lfloor{\frac n 2}\rfloor\)
记 \(\displaystyle{g(A)=\bigodot_{i\in A}f(a_i)}\)
答案有关 \(\displaystyle g(Q)=k\) ,考虑结合律:
计答案的形式有:
- \(k\) 为常数:求所有合法答案集 \(Q\) 数量,或求最优合法答案集 \(Q_{ans}\) 等
- 实现: \(\forall Q_l\in U_l,Q_r\in U_r,且g(Q_l)+g(Q_r)=k\) ,令 \(ans=ans+1\) 或 \(Q_{ans}=best(Q_{ans},Q_l\cup Q_r)\)
- 求 \(max/min(k)\) ,或求 \(k\in[l,r]\) 的合法 \(k\) (或在此基础上取最值)等
- 实现: 一般对答案序列排序然后二分
例题
- 求 \(max({\displaystyle(\sum_{i\in Q}a_i)\%m})\) :(下式均在模意义下进行)
注意到由于 \(g(Q_l),g(Q_r)\lt m\) ,使 \(\forall g(Q_l)+g(Q_r)\ge m\) ,有
这样仅有 \(g(Q_l)\) 和 \(g(Q_r)\) 两数对答案产生贡献,否则两数和也会产生贡献。我们考虑完所有 \(g(Q_l)\) 和 \(g(Q_r)\) 对答案的贡献后,再对每个 \(g(Q_l)\) 找 \(g(Q_r)\lt m-g(Q_l)\) 的最大 \(g(Q_r)\) 用 \(g(Q_l)+g(Q_r)\) 对答案贡献一次就好了。
- 求最小 \(size(Q)\) 即 \(\lvert Q\rvert_{min}\) 使 \(\displaystyle{g(Q)=\bigoplus_{i\in Q}a_i=(2^n-1)}\)
直接将异或和用状压维护起来,对所有 \(g(Q_l)\oplus g(Q_r)=(2^n-1)\) ,令 \(ans=min(\lvert Q_l\cup Q_r\rvert)\)
- 给定 \(a_i,p_i\) 求令 \(g(U)=\sum (a_i\times x_i^{p_i})=0\) 的整数解集 \(X\) ( \(x\in[1,150],n\le 6\) )
折半 \(O(150^{\frac n 2})=150^3=3375000\) 采用折半,合并用乘法原理, \(ans=\sum(cnt_{\text{l}}[k]\times cnt_{\text{r}}[-k])\) 。

浙公网安备 33010602011771号