专栏文章

题解:AT_agc036_b [AGC036B] Do Not Duplicate

AT_agc036_b题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min8dxa5
此快照首次捕获于
2025/12/01 22:15
3 个月前
此快照最后确认于
2025/12/01 22:15
3 个月前
查看原文
看到删除操作就可以往这么一个方向上去想了:
nxtinxt_i 代表如果从 ii 开始插入,之后环形插入,第一次出现删空之后再往 ss 里面加数,加入的第一个数的位置。
(这里的位置可能会 >n>n,因为我们在记录位置的同时要记录是第几次走到这里,这样才能应对 kk 轮的变化)
之后直接暴力跳下一个位置。通过打表可以发现通过跳跃位置作为边建出的图是若干个环,因为每一个点都有正好一个入度、一个出度。
通过周期缩环的方式将 kk 次循环操作改为 n+1\le n+1 次操作。因为周期长度必然 n+1\le n+1。紧接着在环上的每一个点暴力跳跃,直到即将超过 n×kn\times k 步。此时还剩下 n\le n 步,裸暴力跳跃即可。
时间复杂度为 O(n)O(n),但未完全理解就会觉得它很抽象。
CPP
#include<bits/stdc++.h>
#define int long long
#define mp(a,b) make_pair(a,b)
using namespace std;

inline int read(){
	int a=0,b=1;
	char c=getchar();
	while(!isdigit(c)){
		if(c=='-')	b=-1;
		c=getchar();
	}
	while(isdigit(c)){
		a=(a<<1)+(a<<3)+(c-'0');
		c=getchar();
	}
	return a*b;
}
inline void write(int x){
	if(x<0)	putchar('-'),x=-x;
	if(x>=10)	write(x/10);
	putchar(x%10+48); 
} 
inline void write1(int x){
	write(x),putchar(' ');
}
inline void write2(int x){
	write(x),putchar('\n');
}
//找从 1 开始的循环节 
const int N=1e6+15;
int n,m,k;
int a[N]; 
int nxt[N];
int nxt_sum[N];	//按数值划分的 nxt  

int lst[N];
int stk[N];
int stk_idx;
#undef int
int main(){
	#define int long long
	n=read(),k=read(),m=n*k;
	for(int i=1;i<=n;i++){
		a[i]=a[i+n]=a[i+2*n]=read();
	}
	//在 long long 范围内 大多数内容都是能够去完成的! 
	for(int i=3*n;i>=1;i--){
		nxt[i]=nxt_sum[a[i]]+1;
		nxt_sum[a[i]]=i;	//代表未来它会出现的位置 
		//实际上要对环进行各种改造 
	}
//	for(int i=1;i<=n;i++){
//		cout<<nxt[i]<<' ';
//	} 
//	cout<<endl;
	int now=1;
	int circle=0;	//代表一个经过点的环长  
	int circle_=0;	//环长 但是要除以数组长度  
	do{
		circle+=nxt[now]-now;
//		cout<<'$'<<circle<<endl;
		now=nxt[now];
		while(now>n)	now-=n;
//		cout<<'$'<<circle<<' '<<now<<endl; 
	}while(now!=1);
//	return 0;
//	cout<<circle<<endl;
	circle_=circle/n;
//	cout<<'&'<<circle<<' '<<circle_<<endl;
	k%=circle_;	//大幅减小环的数目!
//	cout<<'*'<<k<<endl;
	m=n*k;	//距离终点还有最后 m 步!!!!!
	int m1=m;
	now=1;//!!!!! 
	while(1){
		if(m<nxt[now]-now)	break;	//在这里把它弹出!
		m-=nxt[now]-now;
		now=nxt[now];	//继续跳上去!  
		while(now>n)	now-=n;
//		if(now==1)	break; 
	} 
//	m=m1-m;
//	m1%=m; 
//	return 0;
//	cout<<m<<endl; 
	for(int i=m;i>=1;i--){
		int now=n-i+1;
		now=a[now];
		int lst_=lst[now];
//		cout<<'#'<<now<<' '<<lst_<<endl; 
		if(lst_!=0&&lst_<=stk_idx){
//			cout<<"谭总的世界-017"<<endl; 
			for(int j=lst_;j<=stk_idx;j++){
				lst[stk[j]]=0;
			}
			stk_idx=lst_-1;
		}
		else{
			stk_idx++;
			stk[stk_idx]=now;
			lst[now]=stk_idx;
		}
		
//		cout<<'^'<<stk_idx<<endl;
//		cout<<endl;
	}
	for(int i=1;i<=stk_idx;i++){
		write1(stk[i]);
	}
	putchar('\n');
	return 0;
} //一定要挽回罗琪钧的遗憾啊,一定会挽回罗琪钧的遗憾的! 

评论

0 条评论,欢迎与作者交流。

正在加载评论...