1 条题解
-
0
自动搬运
来自洛谷,原作者为

yzy1
Меня мое сердце, в тревожную даль зовёт.搬运于
2025-08-24 22:31:52,当前版本为作者最后更新于2021-06-29 20:47:54,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题目大意
给你一个排列 ,每次可以将第 个元素移到第 个位置,花费 的代价,问最少花费多少代价将这个排列变成 的排列。
大体思路
对于一个数字 ,设它现在的下标为 。它要移动到正确的位置(即数字 的前面一个位置),有两种方式:用一次操作将它「主动」移过去,或者把 之间的数字全部移走,让这个数「被动」跑到这个位置。如果 ,则用两种方式移动均可。否则,只能使用第一种方式。
我们可以用上面的方法,从 至 移动每个数。由于是「倒序」移动,所以当移动数 时, 就已经排好序了,且 的相对位置和未排序前一样。
我们设 表示现在要排 这个数,已经排好 ,且 要放到一开始的序列的第 号位置的最小代价。记 为数字 现在的位置, 为数字 一开始的位置。先来考虑第一种移动方式,我们可以枚举 ,即
注意这里是 而不是 ,因为 是初始序列的下标。
如果使用第二种移动方式,则需要麻烦一些了。根据徐源盛大佬的论文《对一类动态规划问题的研究》,我们可以知道一个性质:当前决策对未来行动的费用影响只与当前决策有关。也就是说,如果 这个数不动,那么可能对以后的决策花费产生影响,具体一点就是初始位置在 之间的数在排序过程中都需要跨越一次 。根据论文,我们知道对于整数 , 跨越 对答案所增加的代价是 。由于「当前决策对未来行动的费用影响只与当前决策有关」,我们可以直接把这个 加进当前决策的花费中。也就是说,对于移动方式二,我们有以下转移方程:
$$dp(i,pos(i))=\min_{j=pos(i+1)}^n\{dp(i+1,j)+(\sum_{k=pos(i)+1}^{j-1}\max\{i-s_k,0\})\} $$转移方程里的那个求和可以在转移的过程中记录,所以该 DP 的时间复杂度为 。
核心代码
memset(dp, 0x3F, sizeof dp); dp[n][n] = 0; per(i, n - 1, 1) { int posi = 1, posj = 1; re(j, pos[i] - 1) posi += (s[j] < i); // 移动方式 1 re(j, n) { posj += (s[j] < i); if (dp[i + 1][j] != 0x3F3F3F3F) dp[i][j] = dp[i + 1][j] + posi + posj; } // 移动方式 2 int sum = 0; rep(j, pos[i] + 1, n) { if (dp[i][pos[i]] > dp[i + 1][j] + sum) dp[i][pos[i]] = dp[i + 1][j] + sum, pre[i] = j; sum += max(0, i - s[j]); } }
- 1
信息
- ID
- 6793
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者