题解 CF1157E【Minimum Array】

容易想到贪心,依次枚举每个 \(a_i\),每次在可重集 \(b\) 中找到比 \(n-a_i\) 大的最小的数(模意义下),输出后把这个数删掉。

但是因为是模意义下,所以二分还需要断环成链,太麻烦了,因此改用并查集优化暴力。具体地,先统计每个数在 \(b\) 中的出现次数,然后维护一个循环链表,链表里每个数指向比它大的最小的存在的数,再加上路径压缩优化即可。

// Problem: CF1157E Minimum Array
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF1157E
// Memory Limit: 250 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

//By: OIer rui_er
#include <bits/stdc++.h>
#define rep(x,y,z) for(int x=(y);x<=(z);x++)
#define per(x,y,z) for(int x=(y);x>=(z);x--)
#define debug(format...) fprintf(stderr, format)
#define fileIO(s) do{freopen(s".in","r",stdin);freopen(s".out","w",stdout);}while(false)
#define likely(exp) __builtin_expect(!!(exp), 1)
#define unlikely(exp) __builtin_expect(!!(exp), 0)
using namespace std;
typedef long long ll;
const int N = 2e5+5;

int n, a[N], b[N], cnt[N], nxt[N];
template<typename T> void chkmin(T& x, T y) {if(x > y) x = y;}
template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;}
int find(int x) {return cnt[x] ? x : nxt[x] = find(nxt[x]);}

int main() {
	scanf("%d", &n);
	rep(i, 1, n) scanf("%d", &a[i]);
	rep(i, 1, n) scanf("%d", &b[i]);
	rep(i, 1, n) ++cnt[b[i]];
	rep(i, 0, n-1) nxt[i] = (i + 1) % n;
	rep(i, 1, n) {
		int ans = find(n-a[i]);
		printf("%d%c", (a[i]+ans)%n, " \n"[i==n]);
		--cnt[ans];
	}
	return 0;
}
posted @ 2023-01-28 17:12  rui_er  阅读(26)  评论(0编辑  收藏  举报