agc036B Do Not Duplicate

Posted serene-shixinyi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了agc036B Do Not Duplicate相关的知识,希望对你有一定的参考价值。

题意:给一个长度为$n$的序列$a_i$和一个数$k$。

现在把$a$序列重复$k$次生成一个数列$b$,然后从第一位开始往一个栈中加入$b_i$ 。

如果这个栈里存在元素与$b_i$相等那么一直pop直到把那个数弹掉然后不加入新数;否则push$b_i$入栈。求全部操作完之后栈中的元素。

$n leq 2  imes 10^5, k leq 10^{12}, a_i leq 2  imes 10^5$

 

循环节。Yyyyyyyk都知道是循环节。

如果当前栈内第一个元素为$x$,则下一次栈空即为下一次遇到$x$。

所以预处理出每个$a_i$下一个和它相同的位置,假设为$j$,将$i$向$j+1$连边,即下次栈首元素为$a[j+1]$。

可以证明最后连出的一定是若干个环而不是基环内向树,因为每个点有唯一出边且有唯一入边。

也就是说1一定可以走回1,一定存在循环节,环长度最大是n,而对于k来说,循环节长度最大为n+1

所以在环上暴力跑出循环节,将k%循环节长度后,剩下的在环上暴力跑,多出来的一点也暴力跑就好

复杂度$O(n)$

场上想到了循环节,也想到了预处理nxt之类的,但是一直在倒着想,然后就想不出来。

 

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 7;
long long n, k, d;
int a[maxn], lst[maxn], to[maxn], zz[maxn], t, hs[maxn];

int main() {
	scanf("%lld%lld", &n, &k);
	for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
	for (int i = n; i; --i) lst[a[i]] = i;
	for (int i = n; i; --i) {
		to[i] = lst[a[i]];
		lst[a[i]] = i;
	}
	int pos = 1;
	do {
		if(to[pos] <= pos) ++d;
		if(to[pos] == n) ++d;
		pos = to[pos] % n + 1;
	}while(pos != 1);
	k %= d;
	if(k == 0) return 0;
	pos = 1;
	while(1) {
		if(to[pos] <= pos) {
			if(k > 1) --k;
			else break;
		}
		pos = to[pos] % n + 1;
	}
	for (int i = pos; i <= n; ++i) {
		if(hs[a[i]]) {
			//cerr << a[i] << endl;
			while(zz[t] != a[i]) 
				hs[zz[t--]] = 0;
			hs[zz[t--]] = 0;
		}
		else {
			hs[a[i]] = 1;
			zz[++t] = a[i];
		}
	}
	for (int i = 1; i <= t; ++i) printf("%d ", zz[i]);
	printf("
");
	return 0;
}

  

以上是关于agc036B Do Not Duplicate的主要内容,如果未能解决你的问题,请参考以下文章

PSI and index do not match: PSI and index do not match

Do not use @ for indentation

Spring not not null验证在kotlin中抛出HttpMessageNotReadableException而不是MethodArgumentNotValidException(示例代

Kotlinspring boot项目中,在Idea下启动,报错@Configuration class 'BugsnagClient' may not be final.(示例代(代

Type Status Report Message /$%7BpageContext.request.contextPath%7D/upload.do Description The origi(代

Flask——The CSRF tokens do not match.