CF vp 新题乱做
由于都是 CF 上非赛时做的题,因此所有代码都可以去 CF 上找我的账号 zimujun 的 submission 查看。
每道题的标题上有题目链接。
1559E Mocha and stars
*2200,考察基本数论函数性质、背包 dp 和前缀和优化的综合应用,属于综合性较强的基础题。
求有多少长度为 \(n\) 的序列 \(\{a_i\}\) 满足 \(\forall i \in [1, n]\cap\mathbb Z, l_i \le a_i \le r_i, \displaystyle\sum_{i = 1} ^ n a_i \le m, \gcd(a_1, a_2, \cdots, a_n) = 1\)。
\(n \le 50, l_i \le r_i \le m \le 10 ^ 5\)。
后面那个 dp 求解就好,由于上界只到 \(\lfloor\dfrac{m}{t}\rfloor\) 因此总的复杂度是 \(O(nm\ln m)\) 的。
具体的,设 \(f(i, j)\) 表示在前 \(i\) 个数中选出的总和为 \(j\) 的方案数,显然有 \(\displaystyle f(0, 0) = 1, f(i, j) = \sum_{k = \lceil\frac{l_i}{t}\rceil} ^ {\lfloor\frac{r_i}{t}\rfloor} f(i - 1, j - k)\),不难发现后面这个转移可以一个前缀和搞掉,最后答案即为 \(\displaystyle \sum_{i \le \lfloor\frac{m}{t} \rfloor} f(n, i)\)。
1550E Stringforces
*2500,考察二分和状压,同时涉及部分贪心策略的应用,解法较为巧妙。
要求使得最小值最大,可以考虑二分一个限制指 \(len\),要求这 \(k\) 种字符连续出现的最大次数都大于 \(len\),然后判断这个限制值是否合法。
可以考虑然把这 \(k\) 个长度为 \(len\) 的连续段放入字符串的一个前缀,因为当没有别的限制的时候,我们肯定会选择贪心地加入,使得已经加入的前缀尽可能短,可以证明这样的构造方案一定不会更劣。
但是现在有确定字符的限制,而且不同种类字母的限制不同(被除了当前种类字字母在内的所有其他字母限制)。看到 \(k \le 17\),考虑状压。
设 \(f(S)\) 表示已经加入的字母种类集合为 \(S\) 时所占前缀的最小长度。通过枚举往集合中新加入的字符刷表转移。最后判断 \(len\) 是否合法即可转化为判断 \(f(\{1,2,\cdots,k\}) \le n\) 是否成立,考虑如何优雅地实现这个转移。
做一个预处理,设 \(next(i,j)\) 表示从第 \(i\) 个位置,放长度为 \(len\) 的第 \(j\) 种字母的连续段,可以放到的最小右端点位置。倒序枚举 \(i\),如果后面 \(len\) 长度内出现了除了 ?
和第 \(j\) 种字母之内的其他字符(通过维护已经扫过去的每一种字符最靠左的位置实现即可),那就把 \(next(i, j)\) 赋值为 \(next(i + 1, j)\),如果没有出现,那就是 \(i + len\)。这样处理一遍的复杂度为 \(O(nk)\)。
完成这个预处理,我们就可以实现这个转移了。
枚举状态和字符转移即可,复杂度为 \(O(k2^k)\)。
总的复杂度为 \(O((nk + k2^k)\log n)\)。
1246C Rock is Push
*2200,考察对题目性质的发现和使用 dp 求解问题的能力。
前几天 vp 的时候没做出来的一道题。
看起来很 npc 的题意,没想到是个 dp,后来一想,如果把方案数按下一步向左还是向下走区分开,那么这样确实满足无后效性。
然后一个前缀和优化就做完了。
很有意思的一道题。
(要是具体做法还不太明白的话私戳我吧)
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步