题意简述
($q$ 组数据)你有两个串,$s$ 和 $t$,长度都是 $n$。现在你可以对 $s$ 做若干次操作:选择某一个字符,把它移到最前面或者最后面(二选一)。
你现在要把 $s$ 变成 $t$,请问最少需要多少步操作。不行输出 $-1$。
$1\le q,n\le100$。
思路
先放结论:求出最长的串 $a$ 使得 $a$ 是 $s$ 的子序列(不一定连续),并且是 $t$ 的子串(必须连续),答案是 $n-|a|$,$|a|$ 表示 $a$ 的长度
怎么想到的
首先我们发现能任意从中间取字符放到首尾,根据某些直觉,我们发现:把不同的往两边放,把相同的留在中间对齐。
那么留在中间的“相同的”部分,想一想,应该是某一段公共子序列。
这一段公共子序列一定是最长公共子序列吗?不一定,发现我们 只能 对 $s$ 操作,不能动 $t$,所以这段公共子序列在 $t$ 中必须是连续的,不能有断开的。
就比如说样例第一个里面的第三组数据,$s=\texttt{“tste”}$,$t=\texttt{“test”}$,最长公共子序列应该是 $\texttt{“tst”}$,长度为 $3$。可是剩下的那一个字符 $\texttt{e}$ 并不能直接归位,因为要让它归位必须去动 $t$,但是我们只能动 $s$。最优策略应该是把 $\texttt{“st”}$ 放在中间,然后把 $\texttt{t}$ 和 $\texttt{e}$ 动两次归位。
然后现在还有一个问题:移动次数一定是 $n-|a|$ 吗?也就是说,剩下的 $n-|a|$ 个不同的恰好一定能在 $n-|a|$ 步之内归位?
分两步证,先证一定不小于这个数,然后证可以做到 $n-|a|$ 步,又因为我们要步数最小,就只能恰好是这个答案了。
一定不小于:如果能小于,那么我们的最长公共子序列 $a$ 就能变的更长了。所以一定不会小于这个数。
一定能取到:在 $t$ 中,由于 $a$ 是一个子串,于是 $t$ 中和 $s$ 不匹配的地方,就是 $t$ 中抠掉 $a$ 剩下的部分,一定是一段前缀加一点后缀。先从右到左遍历剩下的前缀,在 $s$ 中找一个相等的,放到最前面来。再从左到右遍历剩下的后缀,在 $s$ 中找一个相等的,放到最后面来。然后这个步数显然可以做到 $n-|a|$ 步。(附:关于这个从左到右还是从右到左,可以简单的概括为:从里到外)(为啥是从里到外,可以自己手玩一下)
怎么求
枚举这一段公共子序列在 $t$ 中的起点,然后写两个指针,匹配一下即可。
代码
1 |
|