Codeforces Round 910 (Div. 2) - D(思维) E(思维)

Codeforces Round 910 (Div. 2)

D. Absolute Beauty

观察可知,只要当交换的 \(i\)\(j\) 满足 $ max(a_i, b_i) < min(a_j, b_j)$ 或者 $ min(a_i, b_i) > max(a_j, b_j)$ 时,交换之后才会产生正贡献
所以我们只需要找到距离最远的两组 \((a_i, b_i)\) 即可

第一种做法
先找到最右边的,再遍历一遍整个数组,就可以遍历到最左边的

void solve(){
	int n;
	cin >> n;
	ll ans = 0;
	vector<int> a(n), b(n);
	for(int i = 0; i < n; ++ i) cin >> a[i];
	int maxr = 0;
	for(int i = 0; i < n; ++ i){
		cin >> b[i];
		ans += abs(b[i] - a[i]);
		maxr = max(maxr, min(a[i], b[i]));
	}
	ll ext = 0;
	for(int i = 0; i < n; ++ i){
		ext = max(ext, 2ll * (maxr - max(a[i], b[i])));
	}
	cout << ans + ext << '\n';
	return ;
}

第二种做法
对于所有的 i 统计最大的 \(mx1 = a_i + b_i - cha\)\(mx2 = -a_i - b_i - cha\)
\(max(0, mx1 + mx2)\) 即为交换一组 i,j 后可以获得的最大交换贡献

void solve(){
	int n;
	cin >> n;
	vector<int> a(n), b(n);
	for(int i = 0; i < n; ++ i) cin >> a[i];
	for(int i = 0; i < n; ++ i) cin >> b[i];
	ll ans = 0, mx1 = -INF, mx2 = - INF;
	for(int i = 0; i < n; ++ i){
		int cha = abs(a[i] - b[i]);
		ans += cha;
		mx1 = max(mx1, (ll) a[i] + b[i] - cha);
		mx2 = max(mx2, (ll) -a[i] - b[i] - cha);
	}
	ans += max(0ll, mx1 + mx2);
	cout << ans << '\n';
	return ;
}

E. Sofia and Strings

对于题目的操作二,可以发现其可以用于很多次两两交换,使得一个小字符挪到很多个连续的大字符前而不改变大字符间的相对位置

对于原串维护每一个字母出现的位置
对于目标串的每一个字符,它可以由原串中第一个该字符出现的位置挪移过来,如果说当前位置之前存在比其小的字符,那么这些字符必须要被移除,不然挪移就会被阻挡,无法成功,反应在代码上就是对应字符的队列队首出队

void solve(){
	int n, m;
	string s, t;
	cin >> n >> m >> s >> t;
	deque<int> cnt[30];
	for(int i = 0; i < n; ++ i){
		cnt[s[i] - 'a'].push_back(i);
	}
	bool flag = true;
	for(auto ch : t){
		if(cnt[ch - 'a'].size() == 0){
			flag = false; break;
		}
		int pos = cnt[ch - 'a'].front();
		cnt[ch - 'a'].pop_front();
		for(int i = 0; i < ch - 'a'; ++ i){
			while(cnt[i].size() && cnt[i].front() < pos){
				cnt[i].pop_front();
			}
		}
	}
	if(flag) cout << "YES\n";
	else cout << "NO\n";
	return ;
}
posted on 2023-11-21 10:35  Qiansui  阅读(53)  评论(0编辑  收藏  举报