题解:P15267 「UTOI 1B」Chaotic Time Trio

思路

首先看全是零的部分分,如果 \(n\) 不是很小的时候,手模几个发现似乎都可以构造出来,我们考虑转化。

我们把所有的数分成是 \(0\) 的和不是 \(0\) 的,对于不是 \(0\) 的数,我们可以让他两两配对取 \(\operatorname{mex}\) 变成是 \(0\) 的数,此时我们剩下一堆 \(0\),和至多一个非 \(0\) 的数。

分类讨论一下。

如果剩下一个非 \(0\) 的数,考虑怎么用这几个已有 \(0\) 构造出非 \(0\) 的数。

如图:

如果没有剩下非 \(0\) 的数,可以这样构造。

如图:

这样可以轻松解决,注意当 \(n\) 较小的时候需要特判。

代码

int bg = n + 1;
for(int i = 1; i <= n; ++i) if(a[i] != 0){ bg = i; break;}	
int cnt = bg - 1;
for(int i = bg; i + 1 <= n; i += 2)	ans.pb({a[i], a[i + 1]}), cnt++;
if((n - bg + 1) % 2 == 0 && bg != 0){
	int now = 0;
	for(int i = 2; i <= cnt - 2; ++i) ans.pb({0, now}), now = mex(now, 0);
	ans.pb({0, 0});
	ans.pb({now, 1});
	now = mex(now, 1);
	if(now == 0) for(auto [a, b] : ans) cout << a << ' ' << b << '\n';
}
else{
	int now = 0;
	for(int i = 2; i <= cnt; ++i) ans.pb({0, now}), now = mex(now, 0);
	ans.pb({now, a[n]});
	now = mex(now, a[n]);
	if(now == 0) for(auto [a, b] : ans) cout << a << ' ' << b << '\n';
}

造福后人给一个 checker。

inline void check(){
	multiset<int> s;
	for(int i = 1; i <= n; ++i) s.insert(a[i]), cerr << a[i] << ' ';
	cerr << '\n';
	for(auto [a, b] : ans){
		if(s.find(a) != s.end()) s.erase(s.find(a));
		else cerr << "WA" << '\n', assert(0);
		if(s.find(b) != s.end()) s.erase(s.find(b));
		else cerr << "WA" << '\n', assert(0);
		s.insert(mex(a, b));
	}
	if(s.size() > 1) cerr << "WA" << '\n', assert(0);
	if(*s.begin() != 0) cerr << "WA" << '\n',assert(0);
	else cerr << "AC" << '\n';
}
posted @ 2026-02-12 17:38  Super_lollipop  阅读(21)  评论(0)    收藏  举报