I 套题解
T1 背包
暴力 01 背包有 \(20\) 分。
下一个 Sub,贪心选价值最大的物品就行,至此有 \(30\) 分。
再下一个 Sub,这个是关键提示。考虑按顺序考虑每一个物品,不妨研究考虑到第一个物品的时候,由于剩下的所有体积都是 \(2\) 的倍数,如果此时 \(m\) 是奇数,则选择当前物品肯定不劣,否则我们将它的体积当成 \(2\) 即可。然后该考虑体积为 \(2\) 的物品,同理,如果此时 \(m\) 形如 \(4k + 2\),则选择一个当前物品肯定不劣,否则把体积为 \(2\) 的所有物品(一个或两个)合并成一个体积为 \(4\) 的物品。后面以此类推即可。至此有 \(50\) 分。
一般情况下,思路基本相同。按照体积从小往大考虑,设当前体积为 \(p\),下一个体积是 \(q\),那么我们只要留下一个 \(q\) 的倍数即可,因此要在 \(p\) 这里消耗掉 \(\frac{m \bmod q}{p}\) 个,之后把所有剩下的 \(p\) 按照 \(\frac{q}{p}\) 打包起来升级成 \(q\) 就好。可能会出现一种特殊情况:要消耗一个 \(p\) 但是没有了,这时候直接把剩下的体积扔掉就好。至此有 \(100\) 分。
注:\(80\) 分那档给到可能存在的奇怪卡常做法。
T2 大数学
暴力对着题意做是 \(O(n^3) \sim O(n^4)\),有 \(10\) 分。
每次往序列末尾加入一个 pair 来代表 \(x\) 个 \(y\),容易猜出序列总共只会加入 \(O(n)\) 个 pair,使用一个桶记录目前 \(x\) 有几个,然后删除的时候懒删除就能 \(O(n)\) 求出单个区间答案。于是显然可以做到 \(O(nm)\),有 \(30\) 分。
\(l = r\),单次询问一定形如 \(\{x, x - 1\}\)。一次操作之后剩下 \(x + 1\) 个 \(x - 1\)。如果 \(x + 1\) 是偶数那直接结束,答案就是 \(x + (x - 1)(x + 1)\),否则剩一个 \(x - 1\) 继续往后做。简单手玩即可推出式子。至此 \(40\) 分。
\(a_i = i\),单次询问的序列一定形如 \(\{2, 3, 4, 5, 1, 2, 3, 4\}\) 这样,除了 \(r\) 和 \(l - 1\) 全都两两相消了,剩下 \(r\) 和 \(l - 1\) 分别继续往后做。只要 \(l \neq r\),\(r + 1\) 和 \(l\) 就会相隔至少一个数,此时这两部分相互独立,两部分的答案加起来即可。\(l = r\) 做上一问。至此 \(50\) 分。
正解的情况,将区间写成若干值域连续段,不同段显然互不影响。先考虑 \(L \neq R\),对于一段 \([L, R]\),会累加 \(R\) 和 \(L - 1\) 的贡献,因此一个数被累加贡献是 \(x\) 存在且 \(x + 1\) 不存在以及 \(x\) 存在且 \(x - 1\) 不存在。对于 \(L = R\),是 \(x\) 存在且 \(x + 1\) 和 \(x - 1\) 均不存在。可以直接 \(O(n^2 + m)\) 预处理所有区间后回答,或者直接莫队 \(O(n \sqrt m)\),都是 \(70\) 分。
注意到对于询问区间的约束是一个二维数点,直接离线树状数组扫描线即可,复杂度 \(O(n \log n)\),可以通过。
T3 刷题
首先,搜子根据写的好不好有 \(10 \sim 20\) 分。后者可能需要一些剪枝。
考虑到题干中的按位操作,以及数据范围里神奇的 \(2^{n - i} - 1\),我们都应该考虑拆位。对于拆出来的每一位,我们能做的有效操作只有前缀推成 \(1\) 以及后缀推成 \(0\)。也就是说,每一位都要满足 \(1\) 位于一个前缀中。我们设 \(c_i\) 表示第 \(i\) 位的目标状态有几个 \(1\),\(d_i\) 表示当前第 \(i\) 为有几个 \(1\),那我们可以进行的操作变为:
- 选择一个集合 \(S\) 以及一个非负整数 \(p\),对于所有 \(i \in S\),进行 \(d_i = \max(d_i, p)\),花费 \(f_S\) 的代价。
- 选择一个集合 \(S\) 以及一个非负整数 \(p\),对于所有 \(i \in S\),进行 \(d_i = \min(d_i, p)\),花费 \(g_{U \setminus S}\) 的代价。
这样,问题变成了一个 \(k = \log m\) 的新问题。在这个刻画下,最少需要几次操作是显然容易求的,答案就是序列 \(c\) 中不同数字个数。这样就通过了 \(f_i = g_i = 1\) 的部分分,结合暴力可以获得 \(20 \sim 30\) 分。
由于只有大小关系,我们只需要记录当前每一个 \(d_i\) 与 \(c_i\) 的大小关系,由于关系有 \(<, =, >\) 三种,所以状态数为 \(O(3^k)\)。考虑暴力进行,暴力求每个状态的转移是 \(O(k 2^k)\),因此总复杂度为 \(O(k 6^k) = O(m^{2.58} \log m)\),拼上 \(f_i = g_i = 1\) 后根据常数可以通过 \(40 \sim 50\) 分。
显然没有这么多有效的转移。我们不妨考虑目前在转移操作 \(1\),那么其实对于当前的 \(>\) 选不选无所谓(因为操作 \(1\) 只能让数字变大)。因此,我们只用枚举 \(<\) 和 \(=\) 中的位。那么,怎么实现“我要求一些位选,一些位不选,剩下爱选不选”呢?我们直接预处理即可,令 \(2\) 表示“\(0\) 或 \(1\)”,预处理时枚举一个三进制数然后对 \(2\) 的那些位子集枚举即可。不难证明,此时复杂度优化到 \(O(k 5^k) = O(m^{2.32} \log m)\)。拼上 \(f_i = g_i = 1\) 后根据常数可以通过 \(60 \sim 70\) 分。
我们每次操作一定都要把一位变成 \(=\),并且不能把 \(=\) 号变掉(否则一定不是最少次数),那么 \(=\) 部分其实也不需要枚举。这样,我们每次只枚举 \(<\) 的子集,按照手法的好坏可以优化到 \(O(k^c 4^k) = O(m^2 \log^c m)(c \in \{1, 2\})\)。只要常数得当,应该都是可以得到 \(100\) 分的。
注:关于部分分,\(n \le 13\) 相关的两档都是启发你想拆位的,\(f_i = g_i\) 启发你想每次操作必须生成 \(=\) 并且不能弄掉 \(=\)。
T4 图论
首先容易发现,两类生成菊花森林分别表示右部点和左部点的度数之积。由于 \(c_1, c_2\) 很小,所以在先忽略 \(1\) 度点的情况下,可以搜出来所有可能的度数多重集,在 \(c \le 10^6\) 的时候容易得出最多的时候合法的度数多重集也只有大约 \(N = 23000\) 种。考虑暴力,枚举左部点多重集和右部点多重集,这里我们设左边当前点数 \(a\) 总度数 \(b\),右边点数 \(c\) 总度数 \(d\)。由于二分图所以最后左部点度数和等于右部点度数和,又因为基环树所以这个度数和还等于总点数。据此,我们可以知道左部点要补 \((d - c) - a\) 个 \(1\) 度点,右部点要补 \((b - a) - c\) 个 \(1\) 度点。补完之后看看怎么计算答案。首先我们乘上一个多重组合数,然后就相当于给定每个点的度数求二分基环森林的个数。这个一看就很像 prufer 序列干的事,但是正常的 prufer 序列既做不了二分图也做不了基环树。于是我们开始发明创造。
首先考虑二分树咋做。我们仿照 prufer 序列,每次删掉最小叶子并往序列中加入父亲,但是有很多的序列不能还原,原因是此时最后一位和此时最小叶子同色,如果考虑去重之类的就走远了。考虑到这个序列天生会分为出现左部点和出现右部点,我们不妨分成两个序列。算法流程同样是每次删最小叶子,然后将父亲加入对应颜色的序列中。随便手玩一下可以发现这是正确的。据此我们可以得到一个经典结论:二分树的数量是 \(A^{B - 1}B^{A - 1}\)。但是这在此题不重要,就是提一嘴而已。容易发现这个 prufer 序列同样有经典的性质,每个点出现次数是其度数减一,所以大概是可以用来做本题的问题的。
继续考虑二分基环树,发现怎么都很难避免环所带来的算重的问题,那我们直接孤立掉环!每次找到最小的一度点删掉做上面的算法流程,直到剩下一个环就停下。在环本身已经确定了的情况下,这个我们发明的 prufer 序列就是对的了吗?其实不然。手玩一下可以发现,在 \(A = 3, B = 4\) 的情况下,假设环上节点是 \(1, 2, 4, 5\),那么在两个序列分别是 1/2/3, 3、6/7 的时候爆炸。可以发现,此时爆炸的原因是两个序列上最后一位都不是环上节点。不难证明,当且仅当出现这种情况会导致序列无法还原,这里留给读者证明。
考虑如何计数。此时我们的序列中非环上点出现次数是度数减一,环上点是度数减二。这太不好看了,于是我们直接在序列后面添加所有环上节点,然后只要把答案除以环长阶乘就好了。现在我们的约束是给定每个值出现次数,序列后 \(k\) 个数字必须不重复。这里我们可以发现,要求序列最后一位不在环上就等价于后 \(k+1\) 个数字不重复。于是此时只要我们能对于一个度数序列求后 \(k\) 位不重复方案数,然后用 \(k\) 的乘起来减去 \(k + 1\) 的乘起来就行了。下面设 \(S\) 是环上点集,推一下式子:
其中 \(g_k\) 为所有大小为 \(k\) 的子集乘积和,显然可以 \(O(m^2)\) 计算,其中 \(m\) 为度数非 \(1\) 点个数,这里把 \(m^2\) 可以简单估到 \(O(\log^2 V)\)。于是复杂度是 \(O(N^2 \log^2 V)\),可以获得不知道多少分。
考虑优化,显然我们负担不起 \(O(N^2)\) 再乘东西,但是我们发现系数只和补的 \(1\) 度点个数有关。以左部点为例,补的 \(1\) 度点除了和自己的 \(a\) 有关以外只和对面的 \(d - c\) 有关。直觉告诉我们这个 \(d - c\) 种类数很少,事实也的确如此,这里只有 \(M = 420\) 种不同的 \(d - c\) 。于是我们对于每个 \(d - c\) 求出所有左部点的度数分拆方案的系数和,枚举右部点计算即可。复杂度为很松的 \(O(NM \log V + N \log^2 V)\)。为啥说很松呢?你环长稍微大一点那个 \(NM\) 都会巨幅减少,完全乘不上一个 \(\log\),并且那个 \(\log^2 V\) 也是不满的,几乎没有几个分拆能跑到这么大,所以其实跑起来的感觉像是 \(O(NM + N \log V)\),因此通过绰绰有余。
浙公网安备 33010602011771号