Codeforces Round #768(Div.2)A~C 题解
A. Min Max Swap
题意
共 t t t ( 1 ≤ t ≤ 100 ) (1≤t≤100) (1≤t≤100) 组测试数据,每组中给出一个数组的元素个数 n n n ( 1 ≤ n ≤ 100 ) (1≤n≤100) (1≤n≤100) ,接下来两行分别是 n n n 个元素,分别为两个数组。可以将两个数组对应位置的元素交换,使得两个数组中最大值的乘积最小,求出最小乘积。
思路
注意读题不要读错了,不然会浪费很多时间 。
找出所有元素中最大的元素,它是一定会被乘到的,我们只需让另外一个最大值最小即可,所以我们应该使大的数尽量往最大元素所在组放,随后找出另一组的最大值即可。
也就是分别求出对应位置比较后的较大值的最大值和较小值的最大值。
总结
一开始心急没仔细看,以为是可以将两个数组中的任意元素互换,浪费了不少时间。以后要好好审题。
AC代码
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
A - Min Max Swap | GNU C++17 | Accepted | 15 ms | 0 KB |
#include<bits/stdc++.h>
using namespace std;
int n;
int a[110];
int b[110];
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
cin >> b[i];
int Max1 = 0;
int Max2 = 0;
for (int i = 1; i <= n; i++) {
Max1 = max(Max1, min(a[i], b[i]));
Max2 = max(Max2, max(a[i], b[i]));
}
cout << Max1 * Max2 << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int tt;
cin >> tt;
while (tt--) {
solve();
}
}
B. Fun with Even Subarrays
题意
t t t ( 1 ≤ t ≤ 2 ⋅ 1 0 4 ) (1≤t≤2⋅10^4) (1≤t≤2⋅104)组元素, n n n ( 1 ≤ n ≤ 2 ⋅ 1 0 5 ) (1≤n≤2⋅10^5) (1≤n≤2⋅105)个元素,可进行的操作如下:
选定一个区间 [ l , r ] [l,r] [l,r] ,将 [ r + 1 , r + r − l ] [r+1,r+r-l] [r+1,r+r−l] 区间内的元素对应复制给区间 [ l , r ] [l,r] [l,r] ,显然这两个区间都需在总区间内。
求出使数组中所有元素相等的最小操作数。
思路
因为它是一个将右边的数复制到左边的操作,所以应该从右边开始操作。如果遇到不同的数,就进行一次操作覆盖,遇到相同的就可以继续推进,操作新覆盖的长度是等于它到起点的长度。
总结
遇到runtime error的报错应该去检查是否存在数组越界、爆栈。
本题我当时写的是将跳转后的点的值改变成右端点,再来进行下一次比较的。那么便出现了一个问题,最后一次跳转是可能到负下标的,那么对数组负下标元素的赋值在我本地是没问题的,但在线上测试时就runtime error了。
AC代码
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
B - Fun with Even Subarrays | GNU C++17 | Accepted | 108 ms | 800 KB |
#include<bits/stdc++.h>
using namespace std;
int n;
int a[200010];
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
int k = n;
int cnt = 0;
int j = 1;
while (k>1) {
if (a[k] == a[k - 1])k--;
else {
int p = k;
k -= j;
if(k>0)a[k] = a[p];
//注意下标不能为负,不然会runtime error
cnt++;
}
j = n - k + 1;
}
cout << cnt << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int tt;
cin >> tt;
while (tt--) {
solve();
}
}
C. And Matching
题意
t t t ( 1 ≤ t ≤ 400 ) (1≤t≤400) (1≤t≤400)组测试,每组给出一个 n n n 和 k k k , 4 ≤ n ≤ 2 16 , 0 ≤ k ≤ n − 1 4≤n≤2^{16}, 0≤k≤n−1 4≤n≤216,0≤k≤n−1 , n = 2 j , j ∈ Z n=2^j,j∈Z n=2j,j∈Z
对于
0
0
0 到
n
−
1
n-1
n−1 的这些数,将其两两分组,使得各组的两个数 a&b
的总和等于
k
k
k ,输出任意一种分组方式,若不行,输出-1。
思路
数据很大,不能暴力枚举,那显然就是一道构造题。
分类讨论,先看一种比较特殊的情况,即
n
=
0
n=0
n=0 时,需要使得所有 a&b
均为 0。
设 x x x 的组员应为 c ( x ) c(x) c(x) ,那么怎么求 c ( x ) c(x) c(x) 呢?
由于同一为一,不然则为0,所以不同的时候一定是0那么就可以将 x x x 按位取反,求得 c ( x ) c(x) c(x)
又可以发现由于
n
=
2
j
n=2^j
n=2j,
n
−
1
n−1
n−1 转化成二进制便全由1组成,令 x^(n-1)
,即可使得
x
x
x 按位取反,求得
c
(
x
)
c(x)
c(x)
再分析剩下两种情况。
当 0 < k < n − 1 0<k<n−1 0<k<n−1 时,使 0 和 c ( k ) c(k) c(k) 配对, k k k 和 n − 1 n-1 n−1 配对即可。
当 k = n − 1 k=n-1 k=n−1 时,若 n = 4 n=4 n=4 显然输出 -1;其余情况,使 0 0 0 和 2 2 2 配, n − 1 n-1 n−1 和 n − 2 n-2 n−2 配, n − 3 n-3 n−3 和 1 1 1 配即可。
总结
对于构造类题目,可以先尝试思考特殊情况,说不定能推广到一般。
AC代码
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
C - And Matching | GNU C++17 | Accepted | 108 ms | 0 KB |
#include<bits/stdc++.h>
using namespace std;
int n;
int c(int x)
{
return x ^ (n - 1);
}
void solve()
{
int k;
cin >> n >> k;
if (k == 0) {
for (int i = 0; i <= n / 2 - 1; i++)
cout << i << ' ' << c(i) << endl;
}
else if (k == n - 1) {
if (n == 4) {
cout << -1 << endl;
}
else {
cout << n - 1 << ' ' << n - 2 << endl;
cout << n - 3 << ' ' << 1 << endl;
cout << 0 << ' ' << 2 << endl;
for (int i = 3; i <= n / 2-1; i++)
cout << i << ' ' << c(i) << endl;
}
}
else {
cout << 0 << ' ' << c(k) << endl;
cout << k << ' ' << n - 1 << endl;
for (int i = 1; i <= n / 2 - 1; i++)
if(i!=k&&i!=c(k))cout << i << ' ' << c(i) << endl;
}
}
int main()
{
int tt;
cin >> tt;
while (tt--) {
solve();
}
return 0;
}