Drop Voicing(最长上升子序列)

赛后第三天才开始补提,太怠惰了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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值