2020牛客暑期多校训练营(第五场) D-Drop Voicing
链接
https://ac.nowcoder.com/acm/contest/5670/D
题意
给定1~n的排列,有两种操作
1:将倒数第二个元素放到最前面
2:将第一个元素放到最后
连续第一种操作若干次称为一段
要求将该排列变为1,2,3,...,n ,且段数尽可能少,输出这个最小值
思路
既然若干次操作1看作一段,那我们不妨将若干次操作1当作一种操作,即选择1~n-1的最右边若干元素,将它们放到最左边
或等价于选择1~n-1的某一元素,将它放在最右边
我们可以发现如果将序列放在环上操作,第二种操作就仅相当于改变数字的下标,不改变元素间的相对位置
所以我们可以将一段操作1等价于在1~n的序列中选择任一元素,将它放在最右边
那么若干段操作1我们就可以等价于将任一元素放在任意位置
于是我们只需找到环上的LIS,将其他不在LIS上的元素放到他们应该在的位置上即可
代码
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ms(a) memset(a, 0, sizeof(a))
#define repu(i, a, b) for (int i = a; i < b; i++)
#define repd(i, a, b) for (int i = a; i > b; i--)
using namespace std;
typedef long long ll;
typedef long double ld;
const int M = int(1e5) + 5;
const int mod = int(1e9) + 7;
int a[1005];
int d[1005];
int lis(int s, int t) {
ms(d);
repu(i, s, t + 1) {
d[i] = 1;
repu(j, s, i) {
if (a[j] < a[i]) {
d[i] = max(d[i], d[j] + 1);
}
}
}
return d[t];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
repu(i, 0, n) { cin >> a[i]; }
repu(i, 0, n) { a[i + n] = a[i]; }
int ans = -1;
repu(i, 0, n + n) { ans = max(ans, lis(i, i + n - 1)); }
cout << n - ans << endl;
return 0;
}
————————————————
心里有光,哪儿都美
心里有光,哪儿都美