题目链接:https://ac.nowcoder.com/acm/contest/5670/D
题目大意:
Miyako想通过Drop-2和Invert两种操作把一个给定的排列变成1,2,...,n,连续做任何次数的Drop-2是一个multi-drop,求需要多少次multi-drop
Drop-2操作可以把p-1位放到首位
Invert操作可以把第一位放到最后
解题思路:
每次操作还是通过环来想。
两种操作就是整体在转圈圈和前n-1项在转圈圈
我们思考一下操作的意义,Invert操作不必多说,Drop-2操作让前n-1项转圈相当于在调整pn和其他的相对位置关系。我们只需要相对位置是1,2,...,n就好,相对位置排好后,通过Invert稍微调整一下使得绝对位置1,2,...,n。
那么问题就变为了去找不在正确的相对位置上的点的个数
我们只需要取环上最长的一个上升子序列,然后调整其它数,即可得到答案
复杂度O(n^3)或O(n^2)
代码这里值得再复习的就是绕圈的取模。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 505;
int a[N], dp[N];
int main()
{
int n, ans = 0, len = 0;
scanf("%d",&n);
for(int i = 1; i <= n; i++) {
scanf("%d",&a[i]);
}
for(int i = 0; i < n; i++)
{
memset(dp, 0, sizeof(dp));
for(int j = 1; j <= n; j++)
{
dp[j] = 1;
for(int k = 1; k < j; k++)
{
if(a[(i + j) % n + 1] > a[(i + k) % n + 1]) dp[j] = max(dp[j], dp[k]+1);
}
len = max(len, dp[j]);
}
ans = max(ans, len);
}
printf("%d\n",n-ans);
}LIS那里可以用二分+贪心优化成nlogn
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 505;
int a[N], dp[N];
int main()
{
int n, ans = 0;
scanf("%d",&n);
for(int i = 1; i <= n; i++) {
scanf("%d",&a[i]);
}
for(int i = 0; i < n; i++)
{
memset(dp, 0, sizeof(dp));
int len = 1;
dp[1] = a[(i + 1) % n + 1];
for(int j = 2; j <= n; ++j)
{
if(a[(i + j) % n + 1] > dp[len])
{
dp[++len] = a[(i + j) % n + 1];
}
else{
int m = lower_bound(dp + 1, dp + len + 1, a[(i + j) % n + 1]) - dp;
dp[m] = a[(i + j) % n + 1];
}
}
ans = max(ans, len);
}
printf("%d\n",n-ans);
}
京公网安备 11010502036488号