【题解】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,...}\) 数组的前缀和:
这个太经典了,我们需要将式子中只出现 \(sum\)。
所以有
答案为 \(sum_{n,A}\),这样我们就可以直接 \(O(nA)\) 转移这个 \(sum\) 数组了。
\(SJJ\):“然并卵,那就再来一次!”:
写好一点:
如果把 \(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\) 次,常数巨大。