P15267 「UTOI 1B」Chaotic Time Trio 题解
题意简述
有一个大小为 \(n\) 的可重集 \(S\),要求进行 \(n-1\) 次操作,每次从 \(S\) 中取出两个元素 \(a\) 和 \(b\) 删除,然后将 \(\operatorname{mex}(a,b)\) 加入集合 \(S\),问 \(S\) 是否可以变为 \(\{0\}\)。
Solution
我们不妨从 \(n\) 较小时的特殊情况开始分析:
-
当 \(n=1\) 时,显然只有 \(S=\{0\}\) 一种情况是成立的;
-
当 \(n=2\) 时,假设 \(S=\{a,b\}\),此时我们进行一次操作会使 \(S=\{\operatorname{}mex(a,b)\}\),则 \(\operatorname{mex}(a,b)=0\),则意味着 \(a\neq0\wedge b\neq 0\) 时 \(S\) 是有解的;
-
当 \(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\) 的讨论,发现这样必然是无解的。
-
-
当 \(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]\)。
-
若 \(cnt_1>2\),此时 \(cnt_1\) 会减 2,保证了 \(cnt_1>0\),即 \(cnt_0<|S|\),同时 \(cnt_0\) 会加 1,保证了 \(cnt_0>0\);
-
若 \(cnt_0>2\),此时 \(cnt_0\) 会减 2,保证了 \(cnt_0>0\),同时 \(cnt_1\) 会加 1,保证了 \(cnt_1>0\),即 \(cnt_0<|S|\);
-
考虑条件 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 矛盾,充分性得证。
-
若 \(|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;
}

浙公网安备 33010602011771号