专栏文章

题解:P12227 「WyOJ Round 1」炽 · 踏浪而歌

P12227题解参与者 3已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@minooprh
此快照首次捕获于
2025/12/02 05:51
3 个月前
此快照最后确认于
2025/12/02 05:51
3 个月前
查看原文

Solution

感觉直接按照题意模拟即可。题目要求次数最少字典序最小,我们尽量使得 iji \ne j。所以直接从前往后枚举第一个数,然后判断一下减掉两个非最大值的数,是否合法(不会使操作次数增加),如果合法或当前数就是最大值,就取剩余非零且 idid 最小的数,否则取最大的数。剩余非零的数字集合明显可以用并查集或 set 维护,维护最大的数及其位置则可以用线段树维护。然后就是还要特判一下当前和为奇数的情况,看能否选择 i,ii,i。感觉实现细节还是有点多的,不过仔细想想应该也能像清楚。

Code

CPP
#include<bits/stdc++.h>
#define lc (id << 1)
#define rc (id << 1 | 1)
using namespace std;
const int N = 5e5 + 10;
int a[N], n, mx[N << 2], pos[N << 2], sum;
inline void pushup(int id) {
	mx[id] = max(mx[lc], mx[rc]);
	if (mx[id] == mx[lc])pos[id] = pos[lc];
	else pos[id] = pos[rc];
}
//mx 维护最大值,pos 维护最大值的下标
inline void build(int id, int l, int r) {
}
inline void update(int id, int p, int l, int r) {
}
vector<pair<int, int> > ans;
set<int> s;
signed main() {
	ios :: sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i ++) {
		cin >> a[i];
		if (a[i])s.insert(i);
		//只有a[i] 非0才能放进 set,因为 set 里存的是非零的下标集
		sum += a[i];
	}
	build(1, 1, n);
	for (int i = 1; i <= n; i ++) {
		if (a[i] && s.find(i) != s.end())s.erase(i);
		if ((sum & 1) && a[i] && sum - 1 >= mx[1] * 2) {
			//sum 为奇数判断是否可以取 i,i
			ans.push_back({i, i});
			update(1, i, 1, n);
			sum --;
			a[i] --;
		}
		while (a[i]) {
			if (!s.size()) {
				//只剩下i这个数了
				ans.push_back({i, i});
				update(1, i, 1, n);
				sum --;
			} else if (a[i] == mx[1] || a[*s.begin()] == mx[1] || sum > mx[1] * 2) {
				//可以取非最大值的两个数或 a[i] 是最大值
				int x = *s.begin();
				ans.push_back({i, x});
				update(1, i, 1, n);
				update(1, x, 1, n);
				a[x] --;
				if (!a[x] && s.find(x) != s.end())s.erase(x);
				sum -= 2;
			} else {
				//只能取最大值
				int x = pos[1];
				ans.push_back({i, x});
				update(1, i, 1, n);
				update(1, x, 1, n);
				a[x] --;
				sum -= 2;
				if (!a[x] && s.find(x) != s.end())s.erase(x);
			}
			a[i] --;
		}
	}
	cout << ans.size() << '\n';
	for (auto p : ans)cout << p.first << ' ' << p.second << '\n';
	return 0;
}

评论

2 条评论,欢迎与作者交流。

正在加载评论...