CF1863C MEX Repetition

去洛谷看我的博客

思路

乍一看,感觉无从下手,于是就先列举了几个例子:

02
10
21
02
 
013
201
320
132
013
 
12345
01234
50123
45012
34501
23450
12345

容易发现周期是 n + 1 n+1 n+1,下面解释理由:

首先因为数量 n n n,且两两各不相同,而值域是 [ 0 , n ] [0,n] [0,n],所以在 [ 0 , n ] [0,n] [0,n] 中,每个数最多存在一个,且有一个数是不存在的,我们假设是 p p p

那么对于 a 1 a_1 a1,第一次一定变为 p p p,于是这个数列中不存在的数就变成原来的 a 1 a_1 a1 了,所以 a 2 a_2 a2 就会变成原来的 a 1 a_1 a1,以此类推,第一次操作后,等于是把数组最后一位删去,整体往后挪一位,然后把第一位变成 p p p

就这样不断地操作,经过 n n n 次, p p p 就会被挪到最后一位,然后下一次就会变为原样,所以周期是 n + 1 n+1 n+1

但是发现直接暴力还是会 TLE,所以做法肯定还要文雅些,既然都在之前找到规律了,我们就可以用上面的规律。

假设 k k k 是取模后的 k k k,那么第 k k k 为一定是 p p p,对于 k k k 前面的位置,应该就是原数组的后半段,比如,第 k − 1 k-1 k1 就是 a n a_n an,所以可以直接计算得到原数组的位置,对于 k k k 后面的位置,也可以同理推出对应的原数组的位置。

AC code

#include <bits/stdc++.h>
using namespace std;
int T,n,k,a[100005];
set<int>s;
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&k),k%=n+1;
		for(int i=0;i<=n;++i) s.insert(i);
		for(int i=1;i<=n;++i) scanf("%d",&a[i]),s.erase(a[i]);
		auto i=s.begin();int p=*i;
		if(!k){for(int i=1;i<=n;++i) printf("%d ",a[i]);puts("");}
		else
		{
			for(int i=1;i<=n;++i)
			{
				if(i<k) printf("%d ",a[n-k+i+1]);
				else if(i==k) printf("%d ",p);
				else printf("%d ",a[i-k]);
			}
			puts("");
		}
		s.erase(p);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值