2 条题解
-
4
题意
给出一个长度为 的序列 , 单调递增,问你有多少个序列 以满足下列条件:
- 是 的一个排列。
分析
我们发现 的值非常小,所以我们考虑使用类似背包的方法考虑每一个 和 对总答案的贡献。
由于 单调递增所以 中的数互不相同,因此我们可以直接考虑分类讨论值 在 中的位置,令 则:
- 若 ,,因此 对答案产生 的贡献。
- 若 ,,因此 对答案产生 的贡献。
- 若 ,,因此 对答案产生 的贡献。
计算答案的问题解决了,但是如何记录 在 中的位置?显然我们只关心 与 的大小关系,并不关心 的具体值。因此我们只需要知道有多少中情况满足 ,, 即可。
考虑使用 DP 解决此问题, 表示已考虑 部分, 中有 个位置尚未确定值,且 部分对总答案的贡献为 的方案数。转移时枚举 与 的大小关系和 是否确定值即可。 不确定值时即意味 将用 的数填充, 确定值时即意味 将用 的数填充。
具体转移见代码,建议手画几个图细心分析。
代码
-
4
50 分:
暴力枚举即可
100 分:
设输入的序列为 。容易发现,如果我们按原序列从左往右扫,扫到第 个位置时,我们要考虑的是这一个位置要填什么以及 要填到哪个位置上。
并且一共只有 5 种情况:
- 填到 上;
- 拿一个比 小的数填到 上并且 填到比 小的位置上;
- 拿一个比 小的数填到 上并且 填到比 大的位置上;
- 拿一个比 大的数填到 上并且 填到比 大的位置上;
- 拿一个比 大的数填到 上并且 填到比 小的位置上
那么我们记 表示现在填完第 个数,比 小(包括 )的有 个没填,并且算出来的价值为 的方案数。假设我们现在考虑 位填的数,分别考虑以上的五种情况。不过这里要注意的一点就是当这个位置填的数比它小时,是无法确定究竟是 个当中的哪一个,因此这一部分的价值需要在之前填上 这一位的时候就统计在答案中。
为了方便表述,借助标程的代码段进行解释(一些边界判断和取模略去):
f[i+1][j][p+a[i+1]] += f[i][j][p];//第 i+1 位填 a[i+1],不会产生新的未填项,并且产生新贡献为 a[i+1] f[i+1][j-1][p] += f[i][j][p]*j*j;//第 i+1 位填比 a[i+1] 小的数并且 a[i+1] 填到比 i+1 小的位置上。减少一个未填项,产生新贡献为 0(这些贡献之前之前已经计算) f[i+1][j][p+a[i+1]] += f[i][j][p]*j;//第 i+1 位填比 a[i+1] 小的数并且 a[i+1] 填到比 i+1 大的位置上。未填项数目不改变,产生新贡献为 a[i+1](贡献来自 a[i+1] 填到的那位) f[i+1][j+1][p+2*a[i+1]] += f[i][j][p];//第 i+1 位填比 a[i+1] 大的数并且 a[i+1] 填到比 i+1 大的位置上。未填项数目 +1,产生新贡献为 2*a[i+1](贡献来自 i+1 位和 a[i+1] 填到的那位) f[i+1][j][p+a[i+1]] += f[i][j][p]*j;//第 i+1 位填比 a[i+1] 大的数并且 a[i+1] 填到比 i+1 小的位置上。未填项数目不改变,产生新贡献为 a[i+1](贡献来自 i+1 位)
- 1
信息
- ID
- 189
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 9
- 标签
- 递交数
- 47
- 已通过
- 4
- 上传者