ABC221H
题面
link
给定\(N,M(\le5\times 10^3)\),你需要对每一个\(k=1,2,..,N\),求出满足以下条件的可重集\(A\)的个数
- \(A\)包含\(k\)个正整数,且\(\sum_{i=1}^kA_i=n\)
- 同一元素的个数不超过\(M\)
题解
想想暴力怎么写:设\(f[i][j]\)表示选了\(i\)个元素,和为\(j\),然后\(1\sim n\)枚举加入的元素,枚举加入的个数,再枚举状态来转移,这样是\(O(n^3\ln n)\)的。
关键:为了避免重复,我们是从小到大枚举的元素,也就暗含了加入元素时递增的性质,这就启发了我们给这个递增的序列做差分。\(b_i=a_i-a_{i-1}\)
这样的话,\(b_i\)的贡献就是\((k-i+1)b_i\),将序列翻转之后就是\(i\times b_i\),这样的话发现\(b_i\)的取值均摊下来只会有\(O(\ln)\)次(因为\(i\times b_i\)如果大于\(j\)就一定不会合法,可以直接break掉)
所以,优化的效果达到了。我们再看一下现在的问题:你需要构造一个序列\(b_i\),满足没有连续\(M\)个\(0\),并且最后一个数是正整数(即翻转前的\(b_1=a_1\))
转移时我们可以枚举非\(0\)位置是谁,然后转移,具体来说
\[f[i][j]=\sum_{k=\max(1,i-m)}^{i-1}\sum_{p|i}f[k][j-p]
\]
然后用前缀和优化掉第一个sum。
启发
- 把递增序列转化成差分序列,然后通过差分后序列会产生贡献的状态少了达到优化的效果!
- 差分由于\(0\)的存在,经常会用到前缀和优化!