Drop Voicing(最长上升子序列)

本文探讨了一种通过Invert和Drop-2操作调整数字序列,使其恢复为有序状态的算法。详细介绍了如何利用最长递增子序列的概念,结合特定操作特性,计算最少操作次数。并提供了实现代码及思路。

赛后第三天才开始补提,太怠惰了qaq,比赛那天不知道咋的困得要死,一天睡了12小时,比赛也没怎么比,几乎睡过去了

题意:
一个数字序列,进行一下两种操作:
①Invert:将第一数字移动到最后一个位置
②Drop-2:将倒数第二个数字移动到第一个位置
连续进行Drop-2操作,记作一个multi-drop,问将数字序列恢复成1,2,。。。n需要多少次mutil-drop操作

对于Invert操作,它不会改变操作前数字序列的相对位置,只是将数字的绝对位置给改变了
对于Drop-2操作,它能够改变数字序列的相对位置和绝对位置,绝对位置的改变对于恢复成目标序列的意义不大,不用考虑,主要考虑的是其使得相对位置改变的作用,进行Invert操作可以将数字序列的绝对位置改变,在进行Drop-2操作,可以达到将一数字移动到任意位置的效果

:
	1 2 5 3 4
	Invert: 3 4 1 2 5
	Drop-2: 1 2 3 4 5
	
	1 5 2 3 4
	Invert: 2 3 4 1 5
	Drop-2: 1 2 3 4 5
	
	1 5 3 2 4
	Invert: 5 2 4 1 5
	Drop-2: 1 3 2 4 5
	Invert: 4 5 1 3 2
	Drop-2: 3 4 5 1 2
	Invert: 1 2 3 4 5

所以我们需要找到不符合条件的数字将其移动到它应该在的位置,所谓的不符合条件即不符合1,2,…n这样规律的数,也就是不符合递增序列的数,所以我们只需要找到一条最长的递增子序列,不在这个序列中的数都是需要进行移动的数,所以答案为序列长度-最长递增子序列,注意由于Invert操作的存在,我们的序列开始位置是不确定的,即我们需要从所有数位置作为开始寻找最长子序列

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;

const int N = 2020;

int n;

int up[N], arr[N];

int find(int k) {
	up[1] = arr[k];
	int len = 1;
	for (int i = k+1; i <=k+n-1 ; i++) {
		if (arr[i] > up[len]) up[++len] = arr[i];
		else {
			int l = 1, r = len;
			while (l <= r) {
				int mid = (l + r) / 2;
				if (up[mid] >= arr[i]) {
					r = mid - 1;
				}
				else {
					l=mid+1;
				}
			}
			up[l] = min(up[l], arr[i]);
		}
	}
	return len;
}


int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &arr[i]);
		arr[i + n] = arr[i];
	}
	int len = 0;
	for (int i = 1; i <= n; i++) {
		len = max(len, find(i));
	}
	printf("%d\n", n - len);
}

补题参考题解:https://blog.nowcoder.net/n/1e4de66e422a47fdb04c246cdb2e30ed

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值