loading...

构造 ad-hoc

[QOJ8174] Set Construction

给定 \(n, m\),构造集合 \(S\),满足:

  • \(\forall x \in S\),\(0 \le x < 2^n\)。
  • \(\forall x, y \in S\),\(x \operatorname{or} y \in S\)。
  • \(\forall x, y \in S\),\(x \operatorname{and} y \in S\)。\(\operatorname{or}\) 和 \(\operatorname{and}\) 都是按位运算。
  • \(0 \in S\),\(2^{n}-1 \in S\)。
  • \(|S| = m\)。

\(2\le n \le 60, 2 \le m \le \textcolor{red}{\frac{n(n+1)}{2}}\)。可以证明在约束条件下构造一定成立。

首先考虑为什么可选值域 \([0, 2^n)\) 这么巨大,\(m\) 却只开到了 \(\textcolor{red}{\frac{n(n+1)}{2}}\)。一件有趣的事情是:这样的限制使得成倍缩减 \(m\) 的速度远快于上界限制 \(\frac{n(n+1)}{2}\) 的减少速度。具体来说,我们希望能够使 \(n,m\) 同步减少,规约到 \((n-1, m/2)\) 之类的子问题。令 \(S\) 在 \(n,m\) 下的某一合法解为 \(f(n, m)\)。

如果 \(m\) 为偶数,考虑如果构造出 \(f(n-1, m/2)\) 怎么构造出 \(f(n, m)\)。由于我们要扩充两倍,所以不得不使得 \(f(n, m)\) 形成这个样子(不需要有什么性质):

\[f(n, m) = \{2a \mid a\in f(n-1,m/2)\} \cup \{2a + 1 \mid a \in f(n-1, m/2)\} \]

这样恰好是两倍,容易发现两个部分无交,且根据位运算性质 \(f(n, m)\) 一定合法。

如果 \(m\) 为奇数,没法直接除以 \(2\),考虑变成 \(\frac{(m - 1)}{2}\),可以先变成 \(f(n-1, m-1)\),就变成偶数情况。减少一个的操作考虑:

\[f(n, m)=\{2a + 1 \mid a \in f(n-1, m-1)\} \mid \{0\} \]

应该不算困难。

另外,如果 \(m \ge \frac{n(n-1)}{2}\) 我们就不必大费周章去搞 \(f(n, m)\) 了,从 \(f(n-1, m)\) 得来。但问题是 \(n-1\) 中是必须要有 \(2^{n-1}-1\) 和 \(0\),但 \(n\) 的要求是必须有 \(2^n - 1\) 和 \(0\)。没办法直接套 \(2a + 1\) 或 \(2a\)。但有一个深刻的观察:

  • \((a \otimes b) \operatorname{and} 1 = (a\operatorname{and} 1) \otimes (b\operatorname{and} 1)\),其中 \(\otimes\) 为任意按位运算。

我们按照奇偶分类后,将偶数乘二倍(保留 \(0\)),奇数乘二倍加一(生成 \(2^{n}-1\)),容易证明封闭性仍满足。

考虑很多很多的边界问题:

  • Q1:在 \(n\) 较小时,\(\frac{n(n+1)}{4} > \frac{n(n-1)}{2}\) 怎么办?

    A1:解方程得到 \(n < 3\) 时满足该情况,所以当 \(n < 3\) 是直接进行暴力搜索。

  • Q2:如果 \(f(n-1, m - 1)\) 不满足 \(m-1 \le \frac{n(n-1)}{2}\) 怎么办?

    A2:实际上是拿 \(f(n-2,\frac{m-1}{2})\) 来找的,中间过程不需要考虑上界问题。

  • 注意 Q2 中的情况边界会稍微大一点:

    \(\frac{(n-2)(n-1)}{2} < \frac{n(n+1)/2 - 1}{2}\),解方程得到:\(n < 6\),在 \(n \le 5\) 时暴力搜索即可。结果你发现你的暴力搜索 + 暴力 check 的复杂度是 \(\mathcal O(2^{2^n}2^{2n})\),\(n = 5\) 时似乎不可行……,你先把它表出来,遇到这种情况直接输出。

你发现 \(n = 5\) 时,所有 \(m<15\) 的取值都可以用上面的递归解决,但是 \(m=15\) 时挂了,所以本地跑一个 \(n=5,m=15\) 的表即可。

所以最后发现这个 \(\frac{n(n+1)}{2}\) 逗我玩呢?!全用来解这个鸟限制了。

[QOJ17155] Fix the Coloring

给定一张已经进行了黑白染色的图,你需要把其中的某些点染成红色,使得:

  • 不存在一条边,其两个端点均为黑色或均为白色。
  • 两个端点均为红点的边形成了一个团。

构造一个染色方案或报告无解。

\(1 \le n, m \le 3000\)。

你发现最困难的限制是红点有且仅有恰好一个非平凡的团,其余全是孤立红点。由于黑白已经染好了,所以每个点恰好有两个状态:染红或不染红。考虑如果不允许存在这个团(也即普通三染色),使用 2-SAT,限制为:

  • 如果一条边违法,那么至少将其一个端点染红。
  • 任意一条边的两个端点至多一个红点。

考虑有一个团,枚举团中一个点 \(u\),那么团中所有点必然与 \(u\) 相邻。反过来,不与 \(u\) 相邻的点不可能存在于团中。考虑重新构造 2-SAT 限制如下:

  • 如果两个点之间不存在边,且均与 \(u\) 相邻:两个点不能都染红色。
  • 如果两个点之间存在边,且至少有一个不与 \(u\) 相邻:两个点不能都染红色。
  • 违法边至少有一个端点要染红。

注意用边 \(\lnot u \to u\) 限制必须选择 \(u\) 为红点,时间复杂度为 \(\mathcal O(n + m + \sum \deg(u)^2) = \mathcal O(nm)\)。

[JOI Open 2018] Xylophone

交互题,有一个隐藏的排列 \(p\),每次询问给出 \(l, r\),交互库会返回 \(\max_{i \in [l, r]}\{p_i\} -\min_{i\in[l, r]}\{p_i\}\),请在不超过 \(10000\) 次询问后给出这个排列(已知 \(1\) 在 \(n\) 前面)。

\(2 \le n \le 5000\)。

询问相邻两个数 \((i, i-1)\) 能够得到 \(|p_i-p_{i-1}|\),唯一问题是不知道符号。

考虑再询问一个 \((i-1, i+1)\)(???)。注意到 \(|p_{i-1}-p_i|\) 和 \(|p_i-p_{i+1}|\)的符号只有 \(4\) 种可能性,全部写出来:

  • \(|p_{i-1}-p_i| < |p_i-p_{i+1}|\)。如果关系是 $$

[QOJ22881] Subset Sums

给定长度为 \(n\) 的序列 \(a\),令其子集和序列排序后为 \(s\)(不去重,包含空集),求 \(\max\limits_{1 \le i < 2^n } \{s_{i}-s_{i-1}\}\)。

\(1 \le n \le 10^6\)

牛牛 Ad-hoc 题。

考虑从小到大排序 \(a\),令 \(p_i = \sum _{j \le i} a_j\),其中 \(p_0 = 0\)。我们可以得到答案的下界:

\[\max \{a_i-p_{i-1}\} \]

这是不是也是答案的上界呢?我们的回答是 Yes。考虑每次加入一个 \(a_i\),子集和会变为:

\[S_i = S_{i-1} \cup \{a_i + v\mid v \in S_{i-1}\} \]

其中 \(S_0 = \{0\}\)。如果得到了 \(S_{i-1}\) 子集和的相邻差值上界 \(d_i\),那么如果 \(a_i > \max_{v\in S_{i-1}} v = p_{i-1}\) 时,两个相并的集合值域没有交集,所以唯一需要更新的相邻差只有 \(a_i-p_{i-1}\)。

如果 \(a_i \le p_{i-1}\),由于排序的性质 \(\min _{v\in S_{i-1}} v < a_i\),所以说两个集合值域相交但不包含。所以只会切碎之前的空隙,使其变得更小,所以说只有可能使前缀的答案变小。所以上界的递推为 \(d_i = \max (d_{i-1}, a_i-p_{i-1})\)。最后得到的上界是 \(\max \{a_i - p_{i-1}\}\)。依据这个结论实现即可。

Rational Bubble Sort

给定长度为 \(n\) 的序列 \(a\),问是否能通过若干次将一对相邻值赋为两个数的平均值操作变为非递减序列。

\(1 \le n \le 10^6\)。

取 \(a\) 的前缀和 \(s\),操作 \((i-1, i)\) 只改变了 \(s_{i-1}\)。这个赋值为平均值的操作实际上做的 \(s_{i-1} \gets \dfrac{s_i + s_{i-2}}{2}\)。

考察含义:将 \((i, s_i)\) 描点后,这就是一个取中点的操作,也就是说每次选择三个点把它们扯成直线,两端不变。

考虑最终状态是使得 \(s\) 下凸,由于点 \(0\) 和点 \(n\) 的不能动,所以下凸的方法必须是把这个拉到 \((0, s_0)\) 与 \((n, s_n)\) 形成的直线下方。

观察,感受,发现只要存在一个低于这个直线的点就可以做到(证明不会)。如果没有,并不能说明就不能不可以,如果所有在直线上方的点都能恰好被扯下来,也就是不存在相邻的高于直线的点,那么经过操作是能够使所有点降到直线上的。

[QOJ18131] Rounddog

对于长为 \(n\) 的序列 \(a\),定义 \(f(a)\) 表示在不改变 LIS 和 LDS 情况下添加若干实数得到序列 \(B\),使得 \(B\) 中数字互不相同,添加个数的最大值。给定排列 \(p\),对 \(p\) 每个前缀求 \(f(p[1,i])\) 的值。

\(n \le 2 \times 10^5\)。

对于每个位置定义 \((f_i, g_i)\) 对表示以 \(i\) 为结尾的 LIS 长度和 LDS 长度。容易发现每个 \((f, g)\) 对最多被一个位置占用:如果 \(i < j\) 满足 \((f_i, g_i) = (f_j, g_j)\),那么若 \(a_i < a_j\),则 \(f_j = f_i+1\) 矛盾;若 \(a_i > a_j\),则 \(g_j = g_i + 1\) 矛盾。令 LIS 长度为 \(U\),\(LDS\) 长度为 \(D\),可以证明,答案的上界是 \(U\times D - |a|\)。但这显然不是下界。

考虑枚举 \(i = 1, 2,\dots, U\) 和 \(j = 1, 2, \dots, D\),在 \(a\) 中我们可以得到信息:\(lis_i\) 表示长度为 \(i\) 的最长上升子序列末尾值的最小值,\(lds_i\) 表示长度为 \(i\) 的最长下降子序列的末尾值的最大值。有如下性质:

\[lis_1 < lis_2 < \dots < lis_U\\ lds_1 > lds_2 > \dots > lds_D \]

考虑钦定某个 \(x\) 填入 \((i, j)\) 对,为了使 \((i, j)\) 不会增长至 \(i+1\) 或 \(j + 1\),必须要 \(lis_i > x > lds_j\),有 \(lis_i > lds_j\)。所以,答案的上界为 \(\displaystyle \sum_{i=1}^U \sum_{j=1}^D [lis_i > lds_j]\)。

考虑构造上界,由于实数集无限稠密,按照 \(i\) 小到大,\(j\) 从大到小填即可。

得到答案式用二分维护 lis 和 lds 序列,BIT 维护答案就可以了。

[CEOI 2017] Mousetrap

一万年以前做的题,感觉性质很不错。但恶谊赛放在 T2 是什么意思。

以 \(t\) 为根,观察到:最后一定是 🐁 不能动了,管理员将其到根路径上的每个分叉全部剪掉,最后再来清理 🐁 到根的路径。

你发现,🐁 一旦开始往下走(远离根方向),那么就不能往根走了(管理员暂时不会清理来时路),那么现在管理员能做的只有减去一个期望往下走最少的一条边断掉。定义 \(f_u\) 表示当 🐁 刚进入 \(u\) 时,管理员将其赶回至 \(u\) 所需最小操作次数。如果 \(u\) 的非父边只有一条,那么直接剪掉这一条就困死 🐁 了。否则考虑管理员一定会剪掉 \(f_v\) 最大的 \((u, v)\) 边, 🐁 一定会走次大值,所以转移为 \(f_u \gets \begin{cases}\mathrm{smx}\{f_v\} + d_u & d_u > 1 \\d_u&d_u \le 1\end{cases}\)。

结果你发现这似乎只能通过 \(m, t\) 相邻的情况,为什么。首先 \(m, t\) 相邻时,🐁 不可能往上走,所以说一开始就往下走了,符合我们的预设条件。

但是不相邻时,🐁 开始时可以向上走一段,找一个更好的出路。我们发现,\(m\) 到 \(t\) 祖先链上的点的 \(f_u\) 没有意义,但是除此以外的 \(f_u\) 仍然有意义,因为 🐁 开始往下走就不能往上走了。但是向上走多少步还是很恶心。在 🐁 向上走的过程中,管理员需要同步进行操作,以尽可能最小化这条祖先链上可能的向下决策。发现答案有单调性,考虑二分,则我们需要剪掉 \(m\) 祖先链的分支边中所有 [\(f_u\) 与 \(u\) 往上的祖先链的分支边个数之和] 小于 \(ans\) 的部分,判断 🐁 能否在剪掉这些边之前走过这些边即可。

posted @ 2026-10-15 15:54  goldspade  阅读(13)  评论(0)    收藏  举报