2020牛客暑期多校训练营第五场Drop Voicing

Drop Voicing

原题请看这里

题目描述:

I n a k a Inaka Inaka创作音乐。今天的排列包括 N N N个音符和弦,用排列 P 1 P_1 P1, P 2 P_2 P2, . . . ... ..., P N P_N PN表示从低到高的音符。她的朋友 M i y a k o Miyako Miyako并通过以下两个操作更改和弦:
D r o p − 2 Drop-2 Drop2:取出第二高音符并将其移至最低位置,即将排列更改为 P N − 1 P_{N-1} PN1, P 1 P_1 P1, P 2 P_2 P2, . . . ... ..., P n − 3 P_{n-3} Pn3, P n − 2 P_{n-2} Pn2, P N P_N PN
反转:取出最低音符并将其移至最高位置,即,将排列更改为 P 2 P_2 P2, P 3 P_3 P3, … … , P N − 1 P_{N-1} PN1, P N P_N PN, P 1 P_1 P1
任意数量的连续 D r o p − 2 Drop-2 Drop2操作都被视为一个 m u l t i − d r o p multi-drop multidrop M i y a k o Miyako Miyako希望以最少的 m u l t i − d r o p multi-drop multidrop数目将排列更改为有序排列 1 1 1, 2 2 2, … … , N N N。请帮助她找到所需的 m u l t i − d r o p multi-drop multidrop数目。

输入描述:

第一行包含整数 N N N ( ( ( 2 2 2 ≤ \leq n n n ≤ \leq 500 500 500 ) ) )-----笔记的数量。第二行包含 N N N个以空格分隔的整数 P 1 P_1 P1 P 2 P_2 P2 … \dots P n P_n Pn-笔记的原始排列。输入保证每个 从 1 1 1 N N N(含)的整数仅在排列中出现一次。

输出描述:

输出一个整数—将排列更改为有序整数所需的最少 m u l t i − d r o p multi-drop multidrop次数

样例:

样例输入1:

6
2 4 5 1 3 6

样例输出1:

2

说明:

An optimal solution with two multi-drops is:
- Invert, 5 times, changing the permutation to 6,2,4,5,1,3;
- Drop-2, 3 times, changing the permutation to 4,5,1,6,2,3;
- Invert, 4 times, changing the permutation to 2,3,4,5,1,6;
- Drop-2, 1 time, changing the permutation to 1,2,3,4,5,6.

样例输入2:

8
8 4 7 3 6 2 5 1

样例输出2:

5

思路:

看到 N N N的取值范围你想到了什么?没错,就是 O ( N 3 ) O(N^3) O(N3) O ( N 2 l o g N ) O(N^2logN) O(N2logN)!看到这个时间复杂度你想到了什么?动态规划,对吧?看到这题面我旁边就有dalao猜用最长不下降子序列…
好了,回归本题。
通过理解题意可以知道操作 D r o p − 2 Drop-2 Drop2其实相当于旋转前 N − 1 N-1 N1个数,反转操作相当于把整个数列旋转,那么我们现在将这两个操作结合一下,发现:两个操作同时进行时等价于将数列中的一个数换个位子,所以我们要求的最小的 m u l t i − d r o p multi-drop multidrop数量其实就是最少移动多少个数才能使整个序列变为不下降的一个序列,于是我们就可以想到只要用动态规划求出这个序列的最长不下降子序列就可以了。
一般的最长不下降子序列求法是 O ( n 2 ) O(n^2) O(n2),更好的求法是二分求最长不下降子序列 O ( n l o g n ) O(nlogn) O(nlogn)
这题还需要枚举数组起点求最小值,具体细节请见代码(我的是 O ( n 3 ) O(n^3) O(n3)
比赛的时候还以为是搜索花了好多时间

AC Code:

#include
#define ll long long
using namespace std;
const int MAXN=2505;
int n,a[MAXN],dp[MAXN],ans;
int zcbxj(int st,int en)
{
	for(int i=st;i<=en;i++)	dp[i]=1;
	int sum=1;
	for(int i=st+1;i<=en;i++)
	{
		for(int j=st;j<i;j++)
			if(a[j]<a[i]) dp[i]=max(dp[i],dp[j]+1);
		sum=max(sum,dp[i]);
	}
	return sum;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",a+i);
		a[i+n]=a[i];
	}
	for(int i=1;i<=n;i++)
		ans=max(ans,zcbxj(i,i+n-1));
	printf("%d\n",n-ans);
}

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