ZLOJ练习35
written on 2022-07-08
这次比赛打得很差,需要好好总结一下。
\(A\) 题比较灵活。首先肯定是要按照价值,以非递减顺序排序。然后考虑题目的本质。发现事实上排列的大体顺序是一定的,唯一有变化的就是那些价值相同的物品,对于这些物品考虑高度的摆放情况。
一开始的错误思路是直接按高度从大到小排序(价值为第一关键字固定),但是这样的话,考虑一组样例:
1 2 2
6 8 5
1 1 2
2 7 1
模拟完这组样例就能明白了,所以这样的贪心策略是错误的,原因是每一组相同的价值元素个数可能不等。因此,正解采用 multiset 来维护相同的价值,每次用元素少的去匹配元素多的。因为是multiset,支持贪心匹配,也就是二分找到对面恰好大于或小于的元素,然后同时加。这样既保证了解法的正确性,也便于实现。这类题以后应当要有感觉,就是用一些数据结构帮助贪心地选择。
\(B\) 题,2月的时候做过,但是那个时候没有完全掌握这题的精髓所在。这次补题有许多收获,在此之前,先讲讲这题的大致思路与做法:
一开始看到 \(m\) 的数据范围,很明显一眼状压。但是 \(n\) 的范围较大,因此暴力的一个一个箱子进行状压转移只能拿到 \(50pts\)。对这种需要顺序枚举 \(n\) 的做法,显然优化的余地已经很小了,因此我们考虑换一种思考方式。
首先对原题进行转化,即为 选取若干个二进制数,使他们或起来为全集 \(s\)。
进一步对问题进行抽象,设 \(f_i\) 表示 选取若干个数或起来为状态 \(i\) 的方案数,用 dp 的方法进行转移,最后要求解的答案就是 \(f_s\)。如何计算 \(f_i\) 呢?这里就需要用到容斥进行巧妙地转移,我们设 \(g_i\) 表示选取若干个数或起来为状态 \(i\) 的子集的方案数,那么很显然,假如 \(i\) 有 \(cnt_i\) 个子集(这里将 \(0\)(空集) 也视为子集),那么 \(g_i=2^{cnt_i}\),也就是其中这 \(cnt_i\) 个元素任意选或不选的结果,那么要求解 \(f_i\) 时只要乘以对应的容斥系数即可。特殊地,这题的容斥系数也就是以 “\(i\) 在二进制下与 \(s\) 相差的 \(1\) 的个数”为 \(-1\) 指数的那个数。
\(cnt\) 在读入时初始化,然后子集转移时用高维前缀和(sosdp)即可。
以后看到这类题时,如果是从子集转移的dp,可以考虑先用sosdp,然后按需要使用容斥计算答案。
\(E\) 题也很有价值,现根据指示将此类题套路整理如下:
此类题涉及覆盖操作,我们就可以考虑倒着做,用并查集维护,这样的话每个点最多只会被修改一次,就保证了时间复杂度。
实现很简单,代码可自行查看,细节也不是很多。
\(D\) 题动态规划可拿 \(60 pts\),但是正解的话,需要关注到 \(n\leq 10\) 的数据范围,因此可以考虑搜索,但是暴力搜索时间复杂度是 \(O(26^n)\),会超时,而 \(26^5≈1e7\),因此考虑折半搜索。
这题最难的点其实在于,题目只给了从前往后推的式子,从后往前推的式子需要自己推。首先观察到模数是 \(2^n\) 的形式,那么对于一个正数 \(x\),模上这样的一个数,在位运算中相当于取二进制中的最后 \(n\) 位,(可以感性理解一下)。正因此,我们可以对 xor 与 mod 运算使用交换律,然后我们来看看它的变化形式:
\(k2=k1\cdot 33\) \(xor\) \(t\) \(\%\) \(mod\)
\(k2=k1\cdot 33\) \(\%\) \(mod\) \(xor\) \(t\)
\(k2\) \(xor\) \(t\) \(=k1\cdot 33\) \(\%\) \(mod\)
\(k2\) \(xor\) \(t\) \(=k1\cdot 33\) \(\%\) \(mod\)
∵ \(k2\lt mod\)
∴ \(k1=\) \(k2\) \(\times inv(33)\) \(xor\) \(t\) (\(\%mod\))
(超级不严谨的数学表达)
这就是最终变化形式,然后就可以展开折半搜索了。以后碰到此类题,需要观察数据的范围,以及给出条件隐含的内容。