ABC473

依旧只写出 5 题。

A、B

https://atcoder.jp/contests/abc473/submissions/78772071

https://atcoder.jp/contests/abc473/submissions/78778714

C

树状数组,后面忘了

https://atcoder.jp/contests/abc473/submissions/78790090

D

https://atcoder.jp/contests/abc473/submissions/78809199

看我超级暴力。然后 T 了

发现可以剪一下枝:一个是到最后一个直接用 cur_sum-k 当成最后一个元素,看看能不能用;一个是如果 sum==k,那就直接把搜完的输出,其他的全部输出 \(0\) 就好了。

E

Key Observation:设 \(s_n=\sum_{i=1}^n a_i\),则

\[\begin{aligned} \left(\sum_{i=l}^r a_i\right) \bmod k=0 &\iff (s_r-s_{l-1}) \bmod k=0 \\ &\iff s_r \bmod k - s_{l-1} \bmod k=0 \\ &\iff s_r \bmod k = s_{l-1} \bmod k \end{aligned} \]

设前缀和模 \(k\)\(s_i=(s_{i-1}+a_i)\bmod k\)。若区间 \([l,r]\) 的和能被 \(k\) 整除,则 \(s_r=s_{l-1}\)。问题转化为在 \(s_0,s_1,\dots,s_n\) 中,每遇到一个与之前某个位置相同的余数,就可以多得到 1 分。

\(dp_i\) 表示考虑前 \(i\) 个元素时的最大得分。朴素转移为:

\[dp_i=\max_{0\le j<i}\{dp_j+[s_i = s_j]\} \]

其中 \([P]\) 表示条件 \(P\) 成立时为 \(1\),否则为 \(0\)

这样做是 \(O(n^2)\) 的,会 TLE。观察发现 \(dp\) 数组是单调不降的:对于任意 \(i\),都有 \(dp_i \ge dp_{i-1}\)(大不了把新元素并入最后一段,不加分)。因此对于同一个余数 \(x\),最近一次出现的位置 \(j\) 满足 \(s_j=x\),它的 \(dp_j\) 一定不小于更早出现的同余数位置的 \(dp\) 值。所以转移时只需考虑最近一次出现该余数的位置即可。

\(last_x\) 表示余数 \(x\) 最近一次出现的位置(若未出现过则不存在)。转移可以优化为:

\[dp_i=\max(dp_{i-1},\ dp_{last_{s_i}}+1) \]

其中若 \(last_{s_i}\) 不存在,则第二项忽略。用一个 unordered_map 维护 \(last\),时间复杂度为 \(O(n)\)

实现时注意初始化 \(last_0=0\),表示空前缀余数为 \(0\)。单独处理 \(i=1\):若 \(a_1 \bmod k=0\),则 \(dp_1=1\),否则 \(dp_1=0\),并记录 \(last_{s_1}=1\)。然后从 \(i=2\)\(n\) 按上述转移即可。

https://atcoder.jp/contests/abc473/submissions/78822755

posted @ 2026-08-29 22:05  wwwidk1234  阅读(37)  评论(0)    收藏  举报