ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【做题记录】CF1223D Sequence Sorting

2021-08-06 18:04:03  阅读:202  来源: 互联网

标签:le 边界 Sequence 那么 include Sorting 区间 CF1223D 移动


Problem

CF1223D

题目大意:

给出一个长度为 \(n\) 的序列 \(a\),其中对于 \(\forall 1 \le i \le n,1 \le a_i \le n\)。
每次操作可以把所有值为 \(x\) 的数放到序列的最前面或最后面,问使序列单调上升的最小操作次数是多少。

Solution

首先有两个很重要的性质。

第一个性质,每一种数最多只会被移动一次。
可以用反证法来证明。假设一个数 \(x\) 被移动到了头或尾,那么它再被移动就需要在之后有一个比x大的数移动到了头或一个比 \(x\) 小的数移动到了尾。
那么此时我们可以通过先移动那个数再移动 \(x\) 的方式使它的移动次数又变会 \(1\) 次。

第二个性质,不被移动的数一定是一段连续的数。这里的连续指的是在数值上相邻两种数的差值为 \(1\)。
如果不是一段连续的数,那么说明中间间隔的那些数是需要被移动的,但是移动之后,必然会导致不移动的数的位置错乱,所以是不可能的。

当然,不移动的数也必须本身有序才行。那么接下来的目标就是找到这样满足要求的最长的长度。

我们考虑当数没有重复,即原序列是一个排列时怎么做。
可以使用递推,设 \(f_i\) 表示以数字 \(i\) 为结尾的最长的不移动的数字长度。
很明显,若数字 \(i-1\) 出现在 \(i\) 之前,则 \(f_i=f_{i-1}+1\),也就是继承前面的答案。否则 \(f_i=1\),因为无法继承答案,所以只能是自己一个。
最后对于所有的 \(1 \le i \le n\),取最大的 \(f_i\) 即可。时间复杂度为 \(O(n)\)。

那么对于有重复的数,我们发现只要改动对于能否继承的判断即可。那么什么情况下能继承,什么情况下不能呢?我们把所有的情况都枚举一遍。当然枚举时也有技巧。我们可以把相同的数看做一段区间,最左边的数的位置即为左边界,最右边的数的位置即为右边:



上面三张图中,红色的表示前一个数的区间,蓝色的表示当前数的区间。

我们观察后发现:只有第一张图的情况可以继承答案,即上一个数整个区间都在当前数区间的左边,此时满足上一个区间的右边界比当前数的左边界小。
第二和第三张图都不满足条件,即两个区间交叉或当前数整个区间在上一个数的区间的左边。此时满足上一个数的区间的右边界比当前数区间的左边界大。
那么,我们只要预处理出每个区间的左右边界,就可以做到 \(O(1)\) 判断。预处理可以 \(O(n)\) 做。

递推方式与排列时的方式相同。总时间复杂度为 \(O(n)\)。
另外还有一点需要注意,因为有重复数字,所以必然有一些数字没有出现,若当前数是 \(i\),那么不能从 \(i-1\) 转移过来,应该从上一个出现的数转移过来。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int q,n,a[300005],l[300005],r[300005];
int sum,ans,f[300005];
int main()
{
	q=read();
	while(q--)
	{
		ans=0;
		n=read();
		for(int i=1;i<=n;i++) l[i]=r[i]=f[i]=0;
		for(int i=1;i<=n;i++)
		{
			a[i]=read();
			if(l[a[i]]==0) l[a[i]]=i;
			r[a[i]]=i;
		}//读入并预处理。
		sum=n;//sum表示值不同的数的个数。
		int lst=0;//lst表示上一个出现的数。
		for(int i=1;i<=n;i++)
		{
			if(l[i]==0){sum--;continue;}
			if(l[i]<r[lst]) f[i]=1;//不能继承答案
			else f[i]=f[lst]+1;//能继承答案
			ans=max(ans,f[i]);
			lst=i;
		}
		printf("%d\n",sum-ans);
	}
	return 0;
}

标签:le,边界,Sequence,那么,include,Sorting,区间,CF1223D,移动
来源: https://www.cnblogs.com/mk-oi/p/15109786.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有