cogimyunの小窝

Loading...

P15267 「UTOI 1B」Chaotic Time Trio 题解

题意简述

有一个大小为 \(n\) 的可重集 \(S\),要求进行 \(n-1\) 次操作,每次从 \(S\) 中取出两个元素 \(a\) 和 \(b\) 删除,然后将 \(\operatorname{mex}(a,b)\) 加入集合 \(S\),问 \(S\) 是否可以变为 \(\{0\}\)。

Solution

我们不妨从 \(n\) 较小时的特殊情况开始分析:

  1. 当 \(n=1\) 时,显然只有 \(S=\{0\}\) 一种情况是成立的;

  2. 当 \(n=2\) 时,假设 \(S=\{a,b\}\),此时我们进行一次操作会使 \(S=\{\operatorname{}mex(a,b)\}\),则 \(\operatorname{mex}(a,b)=0\),则意味着 \(a\neq0\wedge b\neq 0\) 时 \(S\) 是有解的;

  3. 当 \(n=3\) 时,假设 \(S=\{a,b,c\}\) 其中 \(a\le b\le c\):

    • 若 \(a>0\) 则不难发现无论怎么操作都会选中两个不为 0 的数,它们的 \(\operatorname{mex}\) 必然为 0,使得新的 \(S'\) 变为 \(n=2\) 且 \(S\) 中有 0 的情况,此时必然无解;

    • 若 \(a=0\wedge b>0\),我们可以对 \(a,b\) 进行操作得到 \(d=\operatorname{mex}(a,b)>0\),此时新的 \(S'=\{d,b\}\),变为了 \(n=2\) 的情况,且 \(b\neq 0\wedge d\neq 0\),所以此时是有解的;

    • 若 \(b=0\wedge c>0\),我们可以对 \(a,b\) 进行操作得到 \(d=\operatorname{mex}(a,b)=1\),于是就和上面一种情况是一样有解的;

    • 若 \(c=0\),我们发现第一次操作会得到 \(d=\operatorname{mex}(0,0)=1\),此时新的 \(S'=\{0,1\}\),根据 \(n=2\) 时对于 \(S\) 的讨论,发现这样必然是无解的。

  4. 当 \(n\geq4\) 时,我们考虑有没有办法将 \(S\) 归约成 \(n=3\) 时的有解情况,我们发现可以进行以下操作保证 \(n\geq 4\) 时 \(S\) 必然有解:

    • 若 \(S\) 中非 0 元素个数大于 2,对任意两个非 0 元素进行操作;

    • 若不满足上一个条件且 \(S\) 中 0 的个数大于 2,对两个 0 进行操作;

    • 若不满足上面两个条件,则对 0 和 任意一个非 0 元素进行操作。

接下来我们证明为什么 \(n\geq 4\) 时 \(S\) 在进行上面的操作后一定可以归约到 \(n=3\) 时的有解情况。

证明:

考虑 \(n=3\) 时有解的条件为 0 的个数是 1 或 2。

记 \(S\) 中 0 的个数为 \(cnt_0\),非 0 元素的个数为 \(cnt_1\),若 \(cnt_0\) 在操作后始终满足 \(cnt_i\in[1,|S|-1]\),则当 \(|S|=3\) 时有 \(cnt_0\) 为 1 或 2,即此时 \(S\) 有解。

则我们转证 \(cnt_0\) 在操作后始终满足 \(cnt_i\in[1,|S|-1]\)。

  1. 若 \(cnt_1>2\),此时 \(cnt_1\) 会减 2,保证了 \(cnt_1>0\),即 \(cnt_0<|S|\),同时 \(cnt_0\) 会加 1,保证了 \(cnt_0>0\);

  2. 若 \(cnt_0>2\),此时 \(cnt_0\) 会减 2,保证了 \(cnt_0>0\),同时 \(cnt_1\) 会加 1,保证了 \(cnt_1>0\),即 \(cnt_0<|S|\);

  3. 考虑条件 1 与条件 2 对于 \(S\) 而言至少有一个满足的充分条件为 \(|S|\geq 5\):

    • 充分性:假设 \(|S|\geq5\) 且 \(S\) 同时不满足条件 1 与条件 2,则 \(cnt_0,cnt_1\in[0,2]\),我们又知 \(|S|=cnt_0+cnt_1\),那么 \(|S|\in[0,4]\),故 \(|S|\geq5\) 与 \(S\) 同时不满足条件 1 和条件 2 矛盾,充分性得证。
  4. 若 \(|S|=4\) 且 \(S\) 同时不满足条件 1 和条件 2,当且仅当 \(cnt_0=cnt_1=2\) 时,此时对于第三种操作,新加入的 \(\operatorname{mex}>0\),则操作后有 \(cnt_0=1,cnt_1=2\),\(cnt_0\) 仍有 \(cnt_0\in[1,|S|-1]\)。

综上所述,\(cnt_0\) 在操作后始终满足 \(cnt_i\in[1,|S|-1]\) 得证,即 \(n\geq 4\) 时 \(S\) 在进行上面的操作后一定可以归约到 \(n=3\) 时的有解情况成立。

于是我们只需要维护 \(cnt_0\) 与 非 0 元素即可,前者使用 \(cnt\) 记录个数,后者使用栈维护具体元素,时间复杂度为 \(O(\sum n)\)。

Code

#include<bits/stdc++.h>
using namespace std;
int t,n,s[200005];
vector<pair<int,int>> tmp;
stack<int> q;
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>t;
    while(t--){
        cin>>n;
        int cnt=0;
        while(!q.empty())q.pop();
        for(int i=1;i<=n;i++){
            cin>>s[i];
            if(s[i])q.push(s[i]);
            else cnt++;
        }
        if(n==1){//n=1时
            if(s[1])cout<<"-1\n";
            continue;
        }else if(n==2){//n=2时
            if(!s[1]||!s[2])cout<<"-1\n";
            else cout<<s[1]<<" "<<s[2]<<"\n";
        }else{//n>=3时
            tmp.clear();
            while(cnt+q.size()>3){//归约成n=3的情况
                if(q.size()>2){//操作1
                    int a=q.top(),b;
                    q.pop();
                    b=q.top();
                    q.pop();
                    tmp.push_back({a,b});
                    cnt++;
                }else if(cnt>2){//操作2
                    cnt-=2;
                    tmp.push_back({0,0});
                    q.push(1);
                }else{//操作3
                    int a=q.top();
                    tmp.push_back({0,a});
                    q.pop();
                    cnt--;
                    if(a==1)q.push(2);
                    else q.push(1);
                }
            }
            if(cnt==3||!cnt)cout<<"-1\n";//n=3时
            else{
                for(auto [a,b]:tmp)cout<<a<<" "<<b<<"\n";
                if(cnt==2){
                    cout<<"0 0\n1 ";
                    cout<<q.top()<<endl;
                }
                else{
                    int t=q.top();
                    cout<<"0 "<<t<<"\n";
                    if(t==1)cout<<"2 ";
                    else cout<<"1 ";
                    q.pop();
                    cout<<q.top()<<"\n";
                }
            }
        }
    }
    return 0;
}
posted @ 2026-03-10 15:48  cogimyun  阅读(24)  评论(0)    收藏  举报