比赛链接:
https://codeforces.com/contest/1421
A. XORwice
题目大意:
给两个数 \(a\) 和 \(b\),找到一个 \(x\) 使 a ^ x + b ^ x 最小,输出这个结果。
思路:
假设 \(a\) 二进制下某一位上为 1,而 \(b\) 对应的这位也是 1,为了使结果变小,我们应该让 \(x\) 的该位为 1,这样子异或之后 \(a\) 和 \(b\) 的该位就都为 0。
由此,我们可以知道 \(x\) 应该等于 \(a\) & \(b\)。结果就变为了 a ^ (a & b) + b ^ (a & b),即 a ^ b。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL T = 1, n, a, b;
void solve(){
scanf("%lld%lld", &a, &b);
cout << (a ^ b) << "\n";
}
int main(){
cin >> T;
while(T--)
solve();
return 0;
}
B. Putting Bricks in the Wall
题目大意:
一张网格图,起点为(1,1),终点为(n,n),除起点外每个格子包含 0 或 1,每次可以到与当前格子有公共边的相邻格子,出发时可以选择数字 0 或者 1,之后只能走含有选择的数的格子,现最多可以改变两个格子的值,使不管选择 1 还是 0 都不能抵达终点,输出改变点的坐标。
思路:
因为只能改变两个格子,所以可以改变起点和终点两边的格子使不能到达终点或走不出起点。
要让不管选择 1 还是 0,都不能抵达终点,那起点两边的格子的值相同,终点两边的格子的值也相同,而且起点两边的格子的值和终点两边格子的值不一样,这样子才会让选择一个数时到达不了终点,选择另一个数时出不了起点。
总共有 16 种情况,用 if 把十六种情况都判断一下就可以了(蒟蒻做法)。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 205;
int T = 1, n;
char s[N][N];
void solve(){
cin >> n;
for (int i = 1; i <= n; ++ i)
for (int j = 1; j <= n; ++ j)
cin >> s[i][j];
char a = s[2][1], b = s[1][2], c = s[n][n - 1], d = s[n - 1][n];
if (a == '0' && b == '0' && c == '0' && d == '0') printf("2\n1 2\n2 1\n");
else if (a == '0' && b == '0' && c == '0' && d == '1') printf("1\n%d %d\n", n, n - 1);
else if (a == '0' && b == '0' && c == '1' && d == '0') printf("1\n%d %d\n", n - 1, n);
else if (a == '0' && b == '0' && c == '1' && d == '1') printf("0\n");
else if (a == '0' && b == '1' && c == '0' && d == '0') printf("1\n2 1\n");
else if (a == '0' && b == '1' && c == '0' && d == '1') printf("2\n1 2\n%d %d\n", n, n - 1);
else if (a == '0' && b == '1' && c == '1' && d == '0') printf("2\n1 2\n%d %d\n", n - 1, n);
else if (a == '0' && b == '1' && c == '1' && d == '1') printf("1\n1 2\n");
else if (a == '1' && b == '0' && c == '0' && d == '0') printf("1\n1 2\n");
else if (a == '1' && b == '0' && c == '0' && d == '1') printf("2\n2 1\n%d %d\n", n, n - 1);
else if (a == '1' && b == '0' && c == '1' && d == '0') printf("2\n1 2\n%d %d\n", n , n - 1);
else if (a == '1' && b == '0' && c == '1' && d == '1') printf("1\n2 1\n");
else if (a == '1' && b == '1' && c == '0' && d == '0') printf("0\n");
else if (a == '1' && b == '1' && c == '0' && d == '1') printf("1\n%d %d\n", n - 1, n);
else if (a == '1' && b == '1' && c == '1' && d == '0') printf("1\n%d %d\n", n, n - 1);
else if (a == '1' && b == '1' && c == '1' && d == '1') printf("2\n1 2\n2 1\n");
}
int main(){
cin >> T;
while(T--)
solve();
return 0;
}
参考榜上大神
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define pb push_back
#define pii pair <int, int>
#define se second
const int N = 205;
int T = 1, n;
char s[N][N];
void solve(){
cin >> n;
for (int i = 1; i <= n; ++ i)
for (int j = 1; j <= n; ++ j)
cin >> s[i][j];
vector <pii> a, b;
(s[1][2] == '0' ? a : b).pb({1, 2});
(s[2][1] == '0' ? a : b).pb({2, 1});
(s[n - 1][n] == '1' ? a : b).pb({n - 1, n});
(s[n][n - 1] == '1' ? a : b).pb({n, n - 1});
if (a.size() > b.size()) swap(a, b);
cout << a.size() << "\n";
for (auto x : a)
cout << x.fi << " " << x.se << "\n";
}
int main(){
cin >> T;
while(T--)
solve();
return 0;
}
C. Palindromifier
题目大意:
给定一个字符串 s,有两种操作。
操作一:选择一个下标 i,将 \(s_2 s_3...s_i\) 翻转后接到字符串开头
操作二:选择一个下标 i,将 \(s_i s_{i + 1}...s_{n - 1}\) 翻转后接到字符串后面
输出方案,使字符串变为回文字符串。
思路:
首先将倒数第二个字符接到最后(第一步),然后将中间所有的字符翻转后接到开头(第二步),接着将第 2 个字符放到开头(第三步),不论什么样的字符串,都可以按照这种方式变为回文串。
我们定义字符串结构为 abcd,a、c、d 都为单个字符,b 可以为任意字符,按照上面的操作,abcd -> abcdc -> dcbabcdc -> cdcbabcdc。
第二步操作让 a 变为最中间的字符,除了两端字符,其余的字符会以 a 为中点对称,通过 1 和 3 两步操作使 c 到两端去,使整体回文。
代码:
#include <bits/stdc++.h>
using namespace std;
int main(){
string s;
cin >> s;
printf("3\nR %d\nL %d\nL 2\n", s.size() - 1, s.size());
return 0;
}
D. Hexagons
题目大意:
有许多蜂巢的地图上,现从(0,0)出发到(x,y),行动的花费与运动方向有关,蜂巢有六条边,已知六个方向的花费及(x,y),求到(x,y)的最小花费。
思路:
首先我们先判断一下每个方向最小的花费,将其定义为 d,容易得到 d1 = min(c1, c6 + c2),d2 = min(c2, c1 + c3),以此类推,我们可以发现规律,某方向的最小花费就是该方向的花费和临近两个方向的花费之和的最小值。
因为我们已经考虑了每个方向的最小值,所以可以将地图分为六块来考虑,六个方向的坐标。
若 x >= y && x >= 0 && y >= 0 那么坐标落在右上角的六分之一的地图中,我们可以找一下所有往这个方向的路径。
到(x,y)的应该有这四条路线,显然路线 2 和 3 是一样的花费,因为我们考虑了每个方向的最小值 (d1 = min(c1, c6 + c2), d2 = min(c2, c1 + c3),其实就是直接走直线和走折线这两种走法取一个最小值,而路线 1 的后半段其实就是路线 2 后半段的折线走法),所以路线 2 和 3 就是最小花费的路线。
按照这种方式将坐标分为六块去讨论就可以了。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL T = 1, x, y, d[6], c[6];
void solve(){
scanf("%lld%lld", &x, &y);
for (int i = 0; i < 6; ++ i)
scanf("%lld", &c[i]);
for (int i = 0; i < 6; ++ i)
d[i] = min(c[i], c[(i + 5) % 6] + c[(i + 1) % 6]);
if (x >= 0 && y >= 0){
if (y >= x) cout << (y - x) * d[1] + x * d[0] << "\n";//右上
else cout << y * d[0] + (x - y) * d[5] << "\n";//上
}
else if (x >= 0 && y <= 0){
cout << -y * d[4] + x * d[5] << "\n";//左上
}
else if (x <= 0 && y >= 0){
cout << y * d[1] + -x * d[2] << "\n";//右下
}
else if (x <= 0 && y <= 0){
if (x >= y) cout << (x - y) * d[4] + -x * d[3] << "\n";//左下
else cout << -y * d[3] + (y - x) * d[2] << "\n";//下
}
}
int main(){
cin >> T;
while(T--)
solve();
return 0;
}