关于MEX的构造题。
有一个 元环,每个元素都和它的相邻元素是“朋友”。此外,额外给定一组 , 和 彼此也是 “朋友”。
求一种给 个元素填数的方案,使得对于任意一个 ,填在 这个位置的数 ,是它所有“朋友”的数组成的集合的 MEX。
从样例可以初步推测,我们填数用到的 并不会很大,只需要尝试在 交替填就好了。
这种情况很简单,不难想到随便选一个起点,一直按照 交替填就行。
由于多了一个位置出来,我们发现刚刚的填数方案行不通了,这时候想一想是否能先钦定一个位置为 ,然后剩下没填的坑只有偶数个了,回到了偶数情况,于是我们往后按照 交替填即可。
最后发现和 这个位置相邻的一定是一个 和一个 ,是合法的,所以这种构造成立。
如果说引入 ,相当于多了一条限制,需要去思考如何小幅度地修改,使得方案合法。
如果 和 是不相同的,那这条多出的限制对于原来的构造实际上没有影响,所以仍然成立。
如果 和 相同,我们任意把其中一个修改为 即可。
首先还是有: 和 不相同,不需要做任何修改,即使这里多了一个为 的数。
然后如果 和 相同呢?这里赛时想了各种天马行空的构造,加了一堆特判,最后可能还是有corner case没判全,遗憾离场。
然而大可不必这样大费周折,只需要在构造的时候把 没有解决的情况 化归到 已经解决的情况上 即可。
这种情况的独特之处就在于: 这个数是独一无二的,整个问题又是建立在环的意义下,所以我们不妨把所有的数同时顺时针移动,直到 旋转到 或者 的位置,就一定能保证 和 处填的数不同,那么这样的构造就是合法的了。
| #include<bits/stdc++.h> |
| using namespace std; |
| int T,n,x,y; |
| const int N=2e5+10; |
| int a[N]; |
| int get(int t) |
| { |
| return t==n?1:t+1; |
| } |
| inline void solve() |
| { |
| cin>>n>>x>>y; |
| if(n%2==0) |
| { |
| for(int i=1;i<=n;++i)a[i]=i%2; |
| if(a[x]==a[y])a[y]=2; |
| } |
| else |
| { |
| a[x]=2; |
| for(int i=get(x),w=0,cnt=1;cnt<=n-1;i=get(i),w^=1,++cnt)a[i]=w; |
| } |
| for(int i=1;i<=n;++i)cout<<a[i]<<" "; |
| cout<<'\n'; |
| } |
| int main() |
| { |
| ios::sync_with_stdio(0); |
| cin.tie(0),cout.tie(0); |
| cin>>T; |
| while(T--) |
| { |
| solve(); |
| } |
| } |
构造题从特殊情况开始考虑,然后尝试用特殊情况的解稍作变换,推及一般情况。
卡题太久就跳。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!