折半搜索

折半搜索

算法原名: \(\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\) ,考虑结合律:

\[\begin{gather} a\odot b\odot c=a\odot(b\odot c)\Longrightarrow \bigodot_{i=1}^n a_i=\bigodot_{i=1}^{mid}a_i\;\odot\bigodot_{i=mid+1}^n a_i\\ \Downarrow\\ \begin{split} \qquad k &=\displaystyle{g(Q)}\\ &=\displaystyle{g(Q_l)\odot g(Q_r)} \end{split} \end{gather} \]

计答案的形式有:

  1. \(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)\)
  1. \(max/min(k)\) ,或求 \(k\in[l,r]\) 的合法 \(k\) (或在此基础上取最值)等
  • 实现: 一般对答案序列排序然后二分

例题

  1. \(max({\displaystyle(\sum_{i\in Q}a_i)\%m})\) :(下式均在模意义下进行)

题解:SSLOJ-2025-8-11-T3.堆石子

注意到由于 \(g(Q_l),g(Q_r)\lt m\) ,使 \(\forall g(Q_l)+g(Q_r)\ge m\) ,有

\[g(Q_l)+g(Q_r) \le min(g(Q_l),g(Q_r))\le max(g(Q_l),g(Q_r)) \]

这样仅有 \(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)\) 对答案贡献一次就好了。

  1. 求最小 \(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)\)

  1. 给定 \(a_i,p_i\) 求令 \(g(U)=\sum (a_i\times x_i^{p_i})=0\) 的整数解集 \(X\) ( \(x\in[1,150],n\le 6\) )

引用jayun学长的题解及代码

折半 \(O(150^{\frac n 2})=150^3=3375000\) 采用折半,合并用乘法原理, \(ans=\sum(cnt_{\text{l}}[k]\times cnt_{\text{r}}[-k])\)

posted @ 2025-08-20 20:55  badn  阅读(23)  评论(0)    收藏  举报