题目链接:D.Drop Voicing
这个题多亏队友的思路才让我醍醐灌顶,有解可寻。
题意
给你n个数的一种排列,对这个数列有两种操作。
- [第一种] Drop-2:
- [第二种] Invert:
任意连续的的Drop-2操作被称为一个muti-drop,问如何操作使得排列转变为1,2,…,n,并且要求muti-drop的数量最少。
题解
我们来看这两个操作,第一种:可以看出与
无关,只是前n-1个数字的循环排列,第二种是这n个数字的循环排列。
循环排列:
此时队友给了我一种思路,这两种操作可以合并为一个操作,就是将最后的一个数字 插入到前(n-1)个数的任意位置。将插入的位置通过第一种操作移动到(n-1)个数里的最高端,然后通过第二种操作将第一个数移动到最高端就达到了插入操作。
这样我们可以通过计算最长上升子序列个数,然后用(长度-最长上升子序列个数)= 要插入的最少数字个数 = min(muti-drop)
由于原数列可以通过第二种操作进行循环排列,所以我们应枚举出每一种循环排列的情况,然后分别求出最长上升子序列的值,取其中的最大值,来保证(长度-最长上升子序列个数)min,来达到 min(muti-drop)。
代码
int p[maxn];
int dp[maxn],g[maxn],n;
int lis(vector<int> a)
{
for(int i=1;i<=n;i++) g[i]=inf;
int maxx=-1;
for(int i=0;i<a.size();i++)
{
int k=lower_bound(g+1, g+n+1, a[i])-g;
dp[i]=k;
g[k]=a[i];
maxx=max(maxx,dp[i]);
}
return maxx;
}
int main()
{
cin >> n;
for(int i=0;i<n;i++) cin >> p[i];
int maxx=-1;
for(int i=0;i<n;i++)
{
vector<int> a;
for(int j=i;j<i+n;j++) a.push_back(p[j%n]);
maxx=max(maxx,lis(a));
}
cout << n-maxx << endl;
}