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();
}

浙公网安备 33010602011771号