SPOJ 的数据是不是有问题啊……
看起来像没有 SPJ 的样子
# 题面
> Linked DarkBZOJ 1431
点击展开/折叠 题面
有 $n$ 个互不相同的数字,你可以花费 $i+j$ 的代价将当前位置为 $i$ 的数挪动到 $j$ 位置上。
最后要把数列变为单调递减,求最小代价。
$n\le1000$
# 解析
由于我一开始读错题了……写的是最后把数列变成单调递增,下面博客的思路也是按照单调递增的写的
数字互不相同,可以先离散化成 $1\sim n$ 的排列。
首先有几个感性理解非常容易,但是真正证明还挺麻烦的结论:
结论1
一个数如果要挪动,一定只挪动一次。
结论2
一定存在一种最优解,满足每次挪动的数的大小递减。
两个结论分开来并不容易证明,但是可以合在一起归纳证明。先考虑最大的数,它的目标位置是 $n$,假如它要挪动,但是先挪到 $i(i< n)$。接下来两种方案:
- 要么位置在 $[i+1,n]$ 的这些数都向前挪(不可能 $[i+1,n]$ 部分向前挪,这样最大值仍需移动,且移动的代价增大);
- 要么最大值再挪动;
相较于直接挪动到 $n$:第一种方案 $[i+1,n]$ 的移动代价都增大了 $1$,第二种方案最后得到的数列完全相同,但是花费更大。所以最大值要挪动就直接“一步到位”。
也因为最大值先移动可以使最大值原位置和 $n$ 之间的数移动的代价至少减少 $1$,能贪心地得到最优解。
综上,如果最大值要移动,则第一个移动且直接移动到末尾;此时最大值对移动代价的影响已经固定,可以“删去”最大值归纳证明子问题。
那么我们从大到小考虑每个数怎么移动,记现在正在考虑数字 $i$ 怎么移动:
- 如果数字 $i$ 要移动,则一定挪动到 $i+1$ 前面一个位置;
- 如果数字 $i$ 已经在 $i+1$ 前面(不一定紧挨着),可以选择不挪动 $i$——此时位置在 $i$ 和 $i+1$ 之间的数必须移动到 $i$ 前面。
考虑了数字 $i$ 的移动后,$i\sim n$ 的相对位置应该是递增的,并且由于只移动了 $i\sim n$,$1\sim i-1$ 的相对位置和初始数列一样。
记 $r_i$ 表示在 $\le i$ 的数的子序列中 $i$ 的位置;
记 $A_i$ 表示 $\le i$ 的数的子序列,$A_i[j]$ 表示 $A_i$ 的从位置 $j$ 开始的后缀。
显然“必须要移动的数”在 $A_{i-1}$ 中表现为一段后缀,即位置在 $i$ 之后的所有 $< i$ 的数字。于是可以设计 DP 状态 $f_{i,j}$ 表示,已经考虑了 $i\sim n$ 的挪动方案,此时 $A_{i-1}$ 中,位置 $j$ 及以后的数字必须移动。
由于 $< i$ 的数的相对位置和初始时相同,而 $< i$ 的子序列中位置小于 $j$ 的数字都在 $i$ 前面,数字 $i$ 现在的位置 恰好就是 $j$。
接下来再讨论几种转移:
- 若数字 $i$ 在 $i+1$ 前面,在 DP 状态中体现为“$i$ 不是必须移动的数字”,则有两种转移:
- $i$ 不移动,则 $r_i$ 之后的 $< i$ 的数($A_i[r_i+1]=A_{i-1}[r_i]$)都必须移动到 $i$ 前面,转移到 $f_{i,r_i}$;
- $i$ 移动到 $i+1$ 前面一个位置,此时必须要挪动的数没有新增($A_{i}[j]=A_{i-1}[j-1]$),转移到 $f_{i,j-1}$;
- 若数字 $i$ 在 $i+1$ 后面,则必须要移动到 $i+1$ 前面一个位置。必须要挪动的数没有新增($A_{i}[j]=A_{i-1}[j]$),转移到 $f_{i,j}$。
还要计算转移的额外代价——挪动 $i$ 时,我们知道 $i+1$ 的真实位置为 $j$,但是我们不知道 $i$ 的真实位置,只知道它在 $A_i$ 中的相对位置。所以我们希望通过相对位置来求得答案。
这就要用到 费用提前计算,注意到 $i$ 在 $A_i$ 中的相对位置与其真实位置相差只有位置在 $i$ 前面并且没有挪动的 $\ge i+1$ 的数的数量。而如果 $i$ 之前有 $\ge i$ 且没有挪动的数,$i$ 是一定要挪动的。所以我们只要在每次决定数 $i$ 不挪动时,将 $i$ 后面 $< i$ 的数的转移代价 $+1$ 即可。
于是上述的三种转移具体为:
若 $r_i< j$,则 $i$ 不必要移动:
若 $i$ 不移动,会使 $A_{i-1}[r_i]$ 这些数的转移的代价加一:
$f_{i+1,j}+(i-1-r_i+1)\to f_{i,r_i}$;
若 $i$ 移动,会使 $A_{i-1}[j-1]$ 的转移代价加一,且移动本身产生代价为 $i+1$ 的真实位置 $j$ 和 $i$ 在 $A_i$ 的相对位置 $r_i$:
$f_{i+1,j}+(i-j+1)+(j-1+r_i)\to f_{i,j-1}$
Hint. $(j-1+r_i)$ 的减一是因为移动到 $i+1$ 的前面;
若 $r_i\ge j$,则 $i$ 必须移动到 $i+1$ 前面一个位置;
移动代价为 $j+r_i$,会使 $A_{i-1}$ 中 $r_i$ 到 $j-1$ 的转移代价加一:
$f_{i+1,j}+(j+r_i)+(r_i-j)\to f_{i,j}$
最后要输出方案就储存一下转移点。
# 源代码
1 | /*Lucky_Glass*/ |