agc036B Do Not Duplicate
题意:给一个长度为n的序列a_i和一个数k。
现在把a序列重复k次生成一个数列b,然后从第一位开始往一个栈中加入b_i 。
如果这个栈里存在元素与b_i相等那么一直pop直到把那个数弹掉然后不加入新数;否则pushb_i入栈。求全部操作完之后栈中的元素。
n \leq 2 \times 10^5, k \leq 10^{12}, a_i \leq 2 \times 10^5
循环节。Yyyyyyyk都知道是循环节。
如果当前栈内第一个元素为x,则下一次栈空即为下一次遇到x。
所以预处理出每个a_i下一个和它相同的位置,假设为j,将i向j+1连边,即下次栈首元素为a[j+1]。
可以证明最后连出的一定是若干个环而不是基环内向树,因为每个点有唯一出边且有唯一入边。
也就是说1一定可以走回1,一定存在循环节,环长度最大是n,而对于k来说,循环节长度最大为n+1
所以在环上暴力跑出循环节,将k%循环节长度后,剩下的在环上暴力跑,多出来的一点也暴力跑就好
复杂度O(n)
场上想到了循环节,也想到了预处理nxt之类的,但是一直在倒着想,然后就想不出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #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 ( "\n" ); return 0; } |
弱者就是会被欺负呀
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 聊一聊 操作系统蓝屏 c0000102 的故障分析
· SQL Server 内存占用高分析
· .NET Core GC计划阶段(plan_phase)底层原理浅谈
· .NET开发智能桌面机器人:用.NET IoT库编写驱动控制两个屏幕
· 用纯.NET开发并制作一个智能桌面机器人:从.NET IoT入门开始
· 我干了两个月的大项目,开源了!
· 推荐一款非常好用的在线 SSH 管理工具
· 聊一聊 操作系统蓝屏 c0000102 的故障分析
· 千万级的大表,如何做性能调优?
· .NET周刊【1月第1期 2025-01-05】