AtCoder Beginner Contest(ABC) 207E - Mod i 题解

方法一

一种简单的 dp 是令dpi,jdp_{i, j}为将前ii个数分成jj个子数组的分法的个数。次转移要遍历ii前的每个位置kk然后前缀前缀和判断sumisumksum_i-sum_k是否是jj的倍数,如果是的话就加上dpk,j1dp_{k, j-1},所以转移是 O(n)O(n)的,总的复杂度是O(n3)O(n^3),会 TLE,于是我们想如何优化。考虑到((sumisumk)modj=0)    (sumisumkmodj)((sum_i-sum_k) \bmod j =0)\iff (sum_i\equiv sum_k \mod j) 也许我们不用遍历所有的kk,只要记录对于每个位置kk, sumkmodi=jsum_k\bmod i=jdpk,i1dp_{k, i-1}的和就行了。于是我们的状态dpi,jdp_{i, j}的定义就变成了在 k 位置结束的子数组,分成ii个子数组并且sumkmodi=jsum_k\bmod i=j的分法的个数。(说实话不是很好理解)

方法二

这种方法和方法一的出发点一样,但转移的时候我们只考虑最大的 k,这是因为两个和为jj的的倍数的子数组拼起来和依然是jj的倍数,所以我们保持一开始的 dp 状态定义,然后用O(n2)O(n^2)的时间预处理出prei,jpre_{i, j},即对于每个位置ii,其左边第一个位置使得sumprei,jsumimodjsum_{pre_{i, j}}\equiv sum_{i}\mod j,转移时考虑两种情况:pre 的位置被分成了jjj1j-1个子数组。