比赛链接:

https://codeforces.com/contest/1672

D. Cyclic Rotation

题目大意:

长为 \(n\) 的序列 \(a\),每一步操作可以选择 \(i\)\(j\),要满足 \(a_i = a_j\),然后让 \(a[l...r] = [a_{l + 1}, a_{l + 2}, ... , a_{r}, a_{l}]\)
给一个序列 \(b\),它是 \(a\) 的排列,问 \(a\) 能不能通过若干次操作变成 \(b\)

思路:

反过来思考,考虑 \(b\) 能否变成 \(a\)
从左往右考虑的话,无法确定哪些元素可以往右移动,所以从右往左考虑。
双指针,其中 \(i\) 指向序列 \(a\)\(j\) 指向序列 \(b\)
\(b_j = b_{j - 1}\),那么 \(b_j\) 一定可以移动到左边的一个位置上。
若不相等,则考虑 \(a_i\) 是不是等于 \(b_j\)
若不是,再考虑这个位置是不是右边移动过来的。
还不是,那就意味着 \(b\) 不能变成 \(a\)
每一个元素是否移动过,可以用 \(map\) 来记录。

代码:

#include <bits/stdc++.h>
using namespace std;
int T, n;
void solve(){
	cin >> n;
	vector <int> a(n + 1), b(n + 1);
	for (int i = 1; i <= n; i ++ )
		cin >> a[i];
	for (int i = 1; i <= n; i ++ )
		cin >> b[i];
	int i = n, j = n;
	map <int, int> c;
	while (i > 0){
		while (b[j] == b[j - 1]){
			c[b[j]] ++ ;
			j -- ;
		}
		if (a[i] == b[j]){
			i -- ;
			j -- ;
		}
		else{
			if (c[a[i]] > 0){
				c[a[i]] --;
				i --;
			}
			else{
				cout << "NO\n";
				return;
			}
		}
	}
	cout << "YES\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	cin >> T;
	while ( T -- )
		solve();
	return 0;
}

E. notepad.exe

题目大意:

\(n\) 个单词,任意两个放在一行的话,中间要用空格隔开。
可以询问一个文本编辑器的长度,系统会返回一个值,即每行最大长度为询问的长度时,最小需要多高去容纳 \(n\) 个单词。
要求输出 \(n\) 个单词所需的文本编辑器的最小空间,空间大小为 \(w * h\)\(w\) 为每行的长度,\(h\) 为高度。

思路:

首先通过二分找到所有单词放在一行的总长。
因为要最优,每一行行末要没有空格,所以枚举每一个高度,从 1 到 \(n\),询问长度去求解。

代码:

#include <bits/stdc++.h>
using namespace std;
int n, ans = 1e9, l = 1, r = 5e6;
int ask(int x){
	cout << "? " << x << "\n";
	int t;
	cin >> t;
	return t;
}
int main(){
	cin >> n;
	while ( l < r ){
		int mid = l + r >> 1;
		if (ask(mid) == 1) r = mid;
		else l = mid + 1;
	}
	for (int i = 1; i <= n; i ++ ){
		int x = ask(l / i);
		if (x) ans = min(ans, l / i * x );
	}
	cout << "! " << ans << "\n";
	return 0;
}

F1. Array Shuffling

题目大意:

给了一个序列 \(a\),每次操作可以选择 \(i\)\(j\),交换 \(a_i\)\(a_j\),要求找到一个序列 \(b\),使得 \(b\) 转化成 \(a\) 的最小操作次数最多。

思路:

最小交换次数的就是总数 - 交换环的次数,证明过程(好多大佬都看这个):https://blog.csdn.net/yunxiaoqinghe/article/details/113153795
交换环的个数就是出现最多的那个数的出现次数。
每一个交换环中元素要依次顺延一位,这样子最后的操作次数才会最多。

代码:

#include <bits/stdc++.h>
using namespace std;
int T, n;
void solve(){
	cin >> n;
	vector <int> a(n), b(n);
	map <int, int> c;
	vector < int > f[n + 1];
	int mx = 0;
	for (int i = 0; i < n; i ++ ){
		cin >> a[i];
		b[i] = a[i];
		c[a[i]] ++ ;
		mx = max(mx, c[a[i]]);
	}
	sort(b.begin(), b.end());
	for (int i = 0; i < n; i ++ )
		f[b[i]].push_back(b[(i + mx) % n]);
	for (int i = 0; i < n; i ++ ){
		cout << f[a[i]].back() << " \n"[i == n - 1];
		f[a[i]].pop_back();
	}
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	cin >> T;
	while ( T -- )
		solve();
	return 0;
}
posted on 2022-04-24 21:52  Hamine  阅读(147)  评论(0编辑  收藏  举报