AtCoder Beginner Contest 381
这场比赛打的冷汗直流,然后无奈寄掉。
C - 11/22 Substring
本以为直接暴力就可以,但是需要加前缀和优化,一个正向处理,一个反向处理,然后查找/
。
abc381_d
赛前2分钟hack掉自己的代码,然后寄掉。
双指针
答案必须是连续的区间,所以想到双指针维护区间合法性,但需要处理以下细节:
-
\(a_r\neq a_{r+1}\) 单个数不合法,右移右指针直到成立,此时与之前区间有断开,右移左指针到右指针。
-
\(vis_{a_r} \neq 0\) 说明当前的数区间包含过,右移左指针直到 \(vis_{a_r}= 0\),移除遍历过的数的标记。
-
\(a_r=a_{r+1} \& a_r=a_{r+2}\) 区间必须断开,如果 \(vis_{a_r}=0\) 要先计算答案,右移右指针,右移左指针到右指针。
#include <bits/stdc++.h> #define int long long #define re register const int N=2e5+10; const int mod=998244353; using namespace std; int n; int a[N]; int vis[N]; int ans=0; void solve(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } a[n+1]=-1; int l=1,r=1; while(l<=n&&r<=n){ int flag=0; if(a[r]==a[r+1]&&a[r]==a[r+2]){ if(!vis[a[r+2]]){ ans=max(ans,r+2-l); } flag=1; while(a[r]==a[r+1]&&a[r]==a[r+2]){ r++; } } while(a[r]!=a[r+1]){ flag=1; r++; } if(r>n){ break; } if(flag){//有断开标记 while(l<r){ vis[a[l]]=0; l++; } } if(vis[a[r]]){ while(vis[a[r]]){ vis[a[l]]=0; l+=2; } } vis[a[r]]=1; if(a[r]!=a[r+2]){ r+=2; } ans=max(ans,r-l); } cout<<ans; } signed main(){ ios::sync_with_stdio(false); cin.tie(nullptr); solve(); return 0; }
[ABC381E] 11/22 Subsequence
赛后的数据才是这个题的精髓,他和C题一样,只是加了个区间,那么我们就找区间,先把/
下标存起来,我就是没存吃大亏,然后二分查找在区间内的下标,然后就遍历计算,这样在赛时是可以过的,赛后就不可以了,我们还可以再二分查找,如果左部分数大于右部分那就缩小右端点,其中不断更新答案最大值。
[ABC381F] 1122 Subsequence
看到数字个数非常少,考虑状压。
我们想要分成并不相交的多个部分,设状态 \(f_s\) 为 \(s\) 状态选出的数中到达最右边的位置,每次从当前状态没有的数字转移,找到 \(f_s\) 右边第一个当前数字的位置 \(now\),再从 \(now\) 右边找到第一个这个数字,这个可以预处理出来。
最后遍历状态如果 \(f_s\le n\) 就说明状态合法,统计选的数字个数。
标签:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)