方法一 #
一种简单的 dp 是令dpi,j为将前i个数分成j个子数组的分法的个数。次转移要遍历i前的每个位置k然后前缀前缀和判断sumi−sumk是否是j的倍数,如果是的话就加上dpk,j−1,所以转移是 O(n)的,总的复杂度是O(n3),会 TLE,于是我们想如何优化。考虑到((sumi−sumk)modj=0)⟺(sumi≡sumkmodj) 也许我们不用遍历所有的k,只要记录对于每个位置k, sumkmodi=j的dpk,i−1的和就行了。于是我们的状态dpi,j的定义就变成了在 k 位置结束的子数组,分成i个子数组并且sumkmodi=j的分法的个数。(说实话不是很好理解)
方法二 #
这种方法和方法一的出发点一样,但转移的时候我们只考虑最大的 k,这是因为两个和为j的的倍数的子数组拼起来和依然是j的倍数,所以我们保持一开始的 dp 状态定义,然后用O(n2)的时间预处理出prei,j,即对于每个位置i,其左边第一个位置使得sumprei,j≡sumimodj,转移时考虑两种情况:pre 的位置被分成了j或j−1个子数组。