牛客 Drop Voicing LIS

题目链接

题目分析:

题目给定了一条串,共有两个操作可以执行,并且只有Drop-2会产生花费。这就是说我们只需要把串转换成周期性的1-n就行了(比如:k—n 1—(k-1))。而连续的多个Drop-2操作仅需一个花费,这也就可以看成是一个操作。现在我们可以对串的任意位置做Drop-2操作(因为可以通过Invert操作来将任意的位置变成倒数第二),而我们又能发现,对一个长度为K的连续字串做了Drop-2操作后,该串其实就往右移动了一个单位。反过来看,可以看成该子串的右边第一个元素左移了k个单位。(k可以任意选择)
现在我们就将题目变成了,每次可以移动一个数字到任意位置,求最小的移动次数使得该串变成 k—n 1—(k-1)的形式。很容易想到,要让移动次数最小,就要充分利用原来的排列,而其中对我们有利的就是有序的子排列,这就将问题变成了求最长上升子序列(LIS)的问题。

AC代码:

#include
#include
using namespace std;
const int MAX_N = 505,INF=1e9;
int dp[MAX_N],arr[MAX_N];
//通过题意的转换后发现其实就是每次每个数字可以移动到某个任意位置,
//要实现最小的移动数就得找满足题意的最长序列,即最长上升子序列。
int main()
{
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)cin >> arr[i];
	int length = 0;//最长上升子串
	for (int cnt = 0; cnt < n; cnt++)//cnt表示起始位置
	{
		fill(dp, dp + MAX_N, INF);
		for (int i = cnt; i < n+cnt; i++)
			*lower_bound(dp, dp + MAX_N, arr[i%n]) = arr[i%n];
		length = max(length, (int)(lower_bound(dp, dp + MAX_N, INF) - dp));
	}
	cout << n - length;
	return 0;
}

你可能感兴趣的:(DP,算法,动态规划)