2025.7.7 NOIP2025模拟赛1
T3:
题目大意:
给定一个大小为 \(N\),由 \(1 \sim N\) 构成的集合,现在问你能有多少种不同的子集,使得子集中任意两个值相与等于两数中一个数,要么为 01。
\(N \le 2^{5000}\),输入时给定二进制。
答案模 \(10^9 + 7\)。
解题思路:
不难发现题目其实是一个集合套集合的形式,要求你统计子集,使得满足两两之间交集为空或包含。
先考虑他的简单形式:\(n = 2^k - 1\) 时。
这个时候我们发现我们不需要考虑这个子集或起来的 1 在哪些位置了,我们值i关心它的个数。
那么为了避免算重,我们考虑设 \(f_{i}\) 表示或起来恰好大小为 \(i\) 的方案数。
那么我们考虑枚举包含第一个 1 的最大的数是几个 1 的。
但有个问题,就是如果我们通过 \(f\) 算的话,必须得 \(O(n^3)\) 才行。
所以套路的,我们再设一个 \(g\),表示或起来不超过 \(i\) 的方案数,但不能选大小为 \(i\) 的集合。
那么考虑如何转移 g。
还是考虑第一个 1 是在一个大小为多少的数中,当然也有可能第一个 1 不出现。
那么
答案就是 \(\sum_{i = 1}^{n} f_{i}\)。
那么我们就能做完 \(N = 2^k - 1\) 了。
然后考虑一般形式。
先分讨一下在最终的子集里最高位的 1 存不存在。
若不存在,那么 \(2 \sim n\) 位没有要求,是 \(\sum_{i = 1}^{n - 1} f_{i}\)。
若存在,那么和上面一样,枚举与第一个 1 在一起的 1 的个数。
那么还得预处理出 \(2^k \sim n\) 中对于每个 i 有多少数的二进制中有 i 个 1。
然后这部分答案是 \(\sum_{i = 1}^{n} cnt_{i} \times g_{i} \times \sum_{j = 0}^{n - i} f_{j}\)。
那么最终时间复杂度为 \(O(n^2)\)。
其实这道数数主要是难在一些不重不漏的二进制的计数技巧,比如:
- f 的定义中强定或起来为 i 个,g 中不强定。
- 枚举第一位与哪些位在一起,这个在状压中也经常出现。
T4:
题目大意:
有一个长度为 \(n\) 的排列,现在确定了前 \(k\) 个位置,让你将后 \(n - k\) 个位置填了,使得 \(i\) 不在 \(i - 1\) 和 \(i + 1\) 中间。
求方案数,答案模 \(10^9 + 7\)。
\(n \le 5000\)。
解题思路:
首先我们发现假设 1 和 2 的相对位置定了,那么所有都定了。
于是我们可以套路的类似插入地记录 dp 状态。
设 \(dp_{i, j, 0/1}\) 表示考虑前 \(i\) 个数,且第 \(i\) 个数相对位置是在第 \(j\) 个位置,且 \(i - 1\) 在 \(i\) 的前/后的方案数。
为了方便,我们可以强定初始时是 \(1 \sim k\) 这些位置。
然后直接暴力转移是 \(O(n^3)\) 的,可以拿差分优化一下。
这个题能这么做其实是很特殊的,因为转移时只有 \(i\) 以及 \(i - 1\) 与 \(i\) 的关系才能影响 \(i + 1\)。
感觉 dp 状态变成动态插入后也是更方便写了。
因为我们如果记录在最后的位置的话,我们不好记录哪些位置被填了。

浙公网安备 33010602011771号