Codeforces Round #956(Div. 2) and ByteRace 2024(A—D题解)

Codeforces Round #956 (Div. 2) and ByteRace 2024

A

签到题

代码:

#include<bits/stdc++.h>
using namespace std;
void work()
{
	int n;
	cin >> n;
	for(int i = 1; i <= n; ++i)
		cout << i << " ";
	cout << '\n';
}
int main()
{
	int t;
	cin >> t;
	while(t--)
		work();	
}

B

题意:

给两个矩阵A, B, 可以选任意长宽大于等于2的子矩阵,令其中一对对角元素+1mod3, 一对+2mod3,问能否用A得到B

思路:

首先可以把+xmod3的操作理解为三进制下按位异或,操作矩阵为P, $ A xor P_1 xor \cdots xorP_n=B$

两边左乘两个A, 得 \(P_1 xor P_2xor\cdots xorP_n = AxorAxorB\)

接下来只需要验证 XOR P 为合法操作序列就ok了, 因为我们选用的操作矩阵是可逆的(\(1xor2=0\)),所以可以模拟操作过程,用同样操作令操作矩阵化为0则合法。

更优的做法是,我们发现操作矩阵的行异或和 and 列异或和为0,再考虑此命题的必要性成立,所以可以通过此方法验证操作矩阵,或者直接通过A,B的行、列异或和来判断是非存在这么一个操作矩阵

代码:

#include<bits/stdc++.h>
using namespace std;
void work()
{
	int n, m;
	cin >> n >> m;
	vector<vector<int>> c(n + 1, vector<int>(m + 1));
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j){
			char d; cin >> d;
			c[i][j] = (d - '0')*2%3;
		}
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j){
			char d; cin >> d;
			c[i][j] += d - '0';
			c[i][j] %= 3;
		}
	vector<int> r(n + 1), col(m + 1);
	for(int i = 1; i <= n; ++i){
		for(int j = 1; j <= m; ++j){
			r[i] += c[i][j]; r[i] %= 3;
			col[j] += c[i][j]; col[j] %= 3;
		}
	}
	bool ans = 0;
	for(int i = 1; i <= n; ++i) ans |= r[i];
	for(int i = 1; i <= m; ++i) ans |= col[i];
	cout << (!ans ? "YES" : "NO") << '\n';
}
int main()
{
	int t;
	cin >> t;
	while(t--)
		work();	
}

C

题意:

三个人分n块蛋糕,每个人对每块蛋糕都有一个估值,三人对所有蛋糕总价值的估值相同为tot,问能否给出三个不相交的区间使得\(\sum_{i = l_a}^{r_a}a_i ,\sum_{i = l_b}^{r_b},\sum_{i=l_c}^{r_c} \ge \lceil tot/3 \rceil\) 成立。

思路:

如果给定了三个人的选取顺序,直接贪心选取,选够了换下一个人,看能否使得三个人都满意。所以可以枚举\(3!\) 种情况。

代码:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void work()
{
	int n;
	cin >> n;
	vector<vector<int>> a(4, vector<int>(n + 1));
	for(int i = 1; i <= 3; ++i)
		for(int j = 1; j <= n; ++j)
			cin >> a[i][j];
	ll tot = 0;
	for(int i = 1; i <= n; ++i) tot += a[1][i];
	vector<int> perm({0, 1, 2, 3});
	do{
		int l = 1, pt = 1;
		vector<int> ans(4);
		ll sum = 0;
		while(l <= n && pt <= 3){
			sum += a[perm[pt]][l++];
			if(sum >= (tot + 2) / 3){
				sum = 0;
				ans[pt++] = l;
			}
		}
		if(pt > 3){
			vector<pair<int, int>> b(4);
			b[perm[1]] = {1, ans[1] - 1};
			b[perm[2]] = {ans[1], ans[2] - 1};
			b[perm[3]] = {ans[2], ans[3] - 1};
			for(int i = 1; i <= 3; ++i){
				cout << b[i].first << " " << b[i].second << " ";
			}
			cout << '\n';
			return;
		}
	}while(next_permutation(perm.begin(), perm.end()));
	cout << "-1\n";
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();	
}

D

题意:

给定两个长度为n的数组A, B(两数组中均无重复元素), 问能否通过任意次\(\forall i-j=l-r, swap(a_i, a_j),swap(b_l,b_r)\) 能否使A等于B

思路:

没有限制我们交换的次数所以可以考虑全用相邻两位交换,发现能通过一般交换操作实现的,一定可以通过相邻两位交换实现,固定其中一个数组让其固定的相邻两位交换偶数次,数组都是不变的,所以只用考虑交换次数奇偶就能判断是否可以使A等于B,偶数YES,奇数NO。对B数组离散,交换次数等于逆序对数,树状数组求解

代码:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void work()
{
	int n;
	cin >> n;
	vector<int> a(n + 1), b(n + 1);
	map<int, int> mp;
	for(int i = 1; i <= n; ++i){
		cin >> a[i];
		mp[a[i]] = i;
	}
	bool ok = 1;
	for(int i = 1; i <= n; ++i){
		cin >> b[i]; if(!mp[b[i]]) ok = 0;
		b[i] = mp[b[i]];
	}
	if(!ok){
		cout << "NO\n";
		return;
	}
	vector<int> tr(n<<1|1);
	auto add = [&](int p){
		for(;p <= n; p += p&-p){
			tr[p]++;
		}
	};
	auto ask = [&](int p){
		int res = 0;
		for(;p; p -= p&-p){
			res += tr[p];
		}
		return res;
	};
	int ans = 0;
	for(int i = 1; i <= n; ++i){
		add(b[i]);
		ans += i - ask(b[i]);
	}
	if(ans&1) cout << "NO\n";
	else cout << "YES\n";
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();	
}
posted @ 2024-07-10 03:05  _yimg  阅读(131)  评论(0)    收藏  举报