【题解】BZOJ2655 calc

一个序列 \(a_1,...,a_n\) 是合法的,当且仅当:

  • 长度为给定的 \(n\)
  • \(a_1,...,a_n\) 都是 \([1,A]\) 中的整数。
  • \(a_1,...,a_n\) 互不相等。

一个序列的值定义为它里面所有数的乘积,即 \(a_1\times...\times a_n\)

两个序列不同当且仅当他们任意一位不一样,求所有不同合法序列的值的和。

\(n\le 500\)

题解

首先一个最简单直接的想法就是 \(dp\)

我们可以先令 \(a\) 递增,最后答案乘以阶乘即可。设 \(dp_{i,j}\) 表示选了 \(a\) 的前 \(i\) 项,最后的第 \(i\) 项为 \(j\),乘积之和为多少。直接转移是 \(O(nA^2)\) 的,前缀和优化一下即可做到 \(O(nA)\) 然而并没有什么用。

\(A\) 太大了,怎么办?大概不是 拉格朗日插值 就是 矩阵快速幂

峰析一下转移式,\(sum_{i,j}\) 表示第 \(i\)\(dp_{i,...}\) 数组的前缀和:

\[dp_{i,j}=\sum\limits_{k=0}^{j-1}dp_{i-1,k}\times j\\=sum_{i-1,j-1}\times j \]

这个太经典了,我们需要将式子中只出现 \(sum\)

所以有

\[sum_{i,j}=sum_{i,j-1}+sum_{i-1,j-1}\times j \]

答案为 \(sum_{n,A}\),这样我们就可以直接 \(O(nA)\) 转移这个 \(sum\) 数组了。

\(SJJ\):“然并卵,那就再来一次!”:

\[sum_{i,j}= \underline{sum_{i,j-1}}+sum_{i-1,j-1}\times j \\ \underline{\underline{(sum_{i,j-2}}+sum_{i-1,j-2}\times(j-1))}+sum_{i-1,j-1}\times j \\ =(\underline{(sum_{i,j-3}+sum_{i-1,j-3}\times(j-2))}+sum_{i-1,j-2}\times(j-1))+sum_{i-1,j-1}\times j \\\\ =~...... \\\\ =sum_{i,0}+\sum\limits_{k=1}^{j-1}sum_{i-1,k}\times(k+1) \\ =\sum\limits_{k=0}^{j-1}sum_{i-1,k}\times(k+1) \]

写好一点:

\[\Rightarrow sum_{i,j}=\sum\limits_{k=0}^{j-1}sum_{i-1,k}\times(k+1) \]

如果把 \(i\) 看成列,\(k\) 看成行,那么实际上就是先对第 \(k\) 行乘上系数 \(k\),然后再求和。所以我们可以得到 \(sum_{i,x}\) 是关于 \(x\) 的多项式,如果第 \(i\) 行是 \(t\) 次多项式,那么 \(i+1\) 行就是 \(t+2\) 次多项式。所以第 \(n\) 行是 \(2n\) 次多项式。

那么肯定考虑拉格朗日插值啦!只需要求出前 \(2n+1\) 个点即可。我们直接用上面的那个 \(dp\) 式,将 \(A\) 改为 \(2n+1\) 就行了。

时间复杂度 \(O(n(2n+1)+(2n+1)^2)=O(6n^2+5n+1)=O(n^2)\),实际将 \(n=500\) 代入运算次数大约为 \(1,500,000\) 次,常数巨大。

posted @ 2022-01-03 19:33  hzy1  阅读(35)  评论(1编辑  收藏  举报