CF2049C 题解

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();
    }
}

总结

构造题从特殊情况开始考虑,然后尝试用特殊情况的解稍作变换,推及一般情况。

卡题太久就跳。

posted @ 2024-12-21 15:20  Hanggoash  阅读(24)  评论(0)    收藏  举报
动态线条
动态线条end