CF2049C 题解
关于MEX的构造题。
题意
有一个 \(n\) 元环,每个元素都和它的相邻元素是“朋友”。此外,额外给定一组 \(x,y\),\(x\) 和 \(y\) 彼此也是 “朋友”。
求一种给 \(n\) 个元素填数的方案,使得对于任意一个 \(i\in[1,n]\),填在 \(i\) 这个位置的数 \(a_i\),是它所有“朋友”的数组成的集合的 MEX。
分析
从样例可以初步推测,我们填数用到的 \(a\) 并不会很大,只需要尝试在 \(0,1,2,3...\) 交替填就好了。
首先考虑不存在 \(x,y\) 限制的情况:
\(n\) 为偶数
这种情况很简单,不难想到随便选一个起点,一直按照 \(0,1\) 交替填就行。
\(n\) 为奇数
由于多了一个位置出来,我们发现刚刚的填数方案行不通了,这时候想一想是否能先钦定一个位置为 \(2\) ,然后剩下没填的坑只有偶数个了,回到了偶数情况,于是我们往后按照 \(0,1\) 交替填即可。
最后发现和 \(2\) 这个位置相邻的一定是一个 \(1\) 和一个 \(0\),是合法的,所以这种构造成立。
考虑 \(x,y\)
如果说引入 \(x,y\),相当于多了一条限制,需要去思考如何小幅度地修改,使得方案合法。
\(n\) 为偶数
如果 \(x\) 和 \(y\) 是不相同的,那这条多出的限制对于原来的构造实际上没有影响,所以仍然成立。
如果 \(x\) 和 \(y\) 相同,我们任意把其中一个修改为 \(2\) 即可。
\(n\) 为奇数
首先还是有:\(x\) 和 \(y\) 不相同,不需要做任何修改,即使这里多了一个为 \(2\) 的数。
然后如果 \(x\) 和 \(y\) 相同呢?这里赛时想了各种天马行空的构造,加了一堆特判,最后可能还是有corner case没判全,遗憾离场。
然而大可不必这样大费周折,只需要在构造的时候把 没有解决的情况 化归到 已经解决的情况上 即可。
这种情况的独特之处就在于:\(2\) 这个数是独一无二的,整个问题又是建立在环的意义下,所以我们不妨把所有的数同时顺时针移动,直到 \(2\) 旋转到 \(x\) 或者 \(y\) 的位置,就一定能保证 \(x\) 和 \(y\) 处填的数不同,那么这样的构造就是合法的了。
Code
#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();}
}
总结
构造题从特殊情况开始考虑,然后尝试用特殊情况的解稍作变换,推及一般情况。
卡题太久就跳。