A. Image
题意
2 X 2 2X2 2X2 的格子,由 26 26 26 种颜色染色。可以对格子进行操作,每次操作可以选择一个格子染成任意一种颜色或者选择二个格子染成同一种颜色。询问需要的最小操作数使得四个格子颜色相同。
题解
分类讨论
v
i
s
[
x
]
vis[x]
vis[x]表示有
x
x
x个格子颜色相同的颜色种类数。
| 答案 | 情况( v i s [ 1 ] , v i s [ 2 ] , v i s [ 3 ] , v i s [ 4 ] vis[1],vis[2],vis[3],vis[4] vis[1],vis[2],vis[3],vis[4]) |
|---|---|
| 0 | ( 0 , 0 , 0 , 1 ) (0,0,0,1) (0,0,0,1) |
| 1 | ( 2 , 1 , 0 , 0 ) (2,1,0,0) (2,1,0,0) |
| 2 | ( 0 , 2 , 0 , 0 ) , ( 1 , 0 , 1 , 0 ) (0,2,0,0),(1,0,1,0) (0,2,0,0),(1,0,1,0) |
| 3 | ( 4 , 0 , 0 , 0 ) (4,0,0,0) (4,0,0,0) |
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int T;
char s[10][10];
int main() {
cin >> T;
while (T--) {
map<char, int>mp;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
char x; cin >> x;
mp[x]++;
}
}
int vis[10] = { 0,0,0,0,0,0,0,0 };
for (auto p : mp) {
vis[p.second]++;
}
if (vis[1] == 4) {
cout << "3\n";
}
else if (vis[2] == 2||vis[3]==1) {
cout << "1\n";
}
else if (vis[4] == 1) {
cout << "0\n";
}
else {
cout << "2\n";
}
}
return 0;
}
B. Deadly Laser
题意
在一个 n ∗ m n * m n∗m 的矩阵中,与 ( s x , s y ) (s_x,s_y) (sx,sy)的曼哈顿距离小于等于 d d d的格子不能走,请问从 ( 1 , 1 ) (1,1) (1,1)移动到 ( n , m ) (n,m) (n,m) 的最短距离。
题解

如图所示,我们会发现不能走的区域是一个正方形,并且只要这个正方形的任意一条边不与矩阵相交,那么就可以以最短距离到达终点。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int T;
int n, m, sx, sy, d;
int main() {
cin >> T;
while (T--) {
cin >> n >> m >> sx >> sy >> d;
if ((sx - d <= 1 && sx + d >= n) || (sy - d <= 1 && sy + d >= m) || (sx - d <= 1 && sy - d <= 1) || (sx + d >= n && sy + d >= m))cout << "-1\n";
else cout << n + m - 2 << "\n";
}
return 0;
}
C. Min-Max Array Transformation
题意
有三个序列 a , b , d a,b,d a,b,d,其中 a i + d i = b i a_i+d_i=b_i ai+di=bi。
给出序列 a , b a,b a,b,序列可以重新排列,询问每个 d i d_i di在重新排列后可以变成的最小值和最大值。
题解
首先,考虑如何求最小值。
序列已经按从小到大排好序,且 a i ≤ b i a_i\leq b_i ai≤bi。
a 1 a 2 a 3 a x a n a_1~~~a_2~~~a_3~~~ a_x~~~a_n a1 a2 a3 ax an
b 1 b 2 b 3 b x b n b_1~~~b_2~~~b_3~~~ b_x~~~b_n b1 b2 b3 bx bn
由于我们需要求 a x + d m i n = b y a_x + d_{min}=b_y ax+dmin=by,那么我们只需要找到大于等于 a x a_x ax的第一个数,则 d m i n d_{min} dmin最小。
那么这样求,会不会使其他位置的 d i d_i di 不满足题设呢?假设 y = 2 y=2 y=2,序列会变成
a 1 a x a 2 a 3 a n a_1~~~a_x~~~a_2~~~ a_3~~~a_n a1 ax a2 a3 an
b 1 b 2 b 3 b x b n b_1~~~b_2~~~b_3~~~ b_x~~~b_n b1 b2 b3 bx bn
仍然满足 a i ≤ b i a_i\leq b_i ai≤bi的条件。
接下来,我们来考虑求最大值的情况。
a 1 a 2 a 3 a 4 a 5 a_1~~~a_2~~~a_3~~~ a_4~~~a_5 a1 a2 a3 a4 a5
b 1 b 2 b 3 b 4 b 5 b_1~~~b_2~~~b_3~~~ b_4~~~b_5 b1 b2 b3 b4 b5
对于 a 1 a_1 a1,如果我们想让 d 1 d_1 d1 尽量大,那么应该选择 d 1 = b 5 − a 1 d_1=b_5-a_1 d1=b5−a1,那么序列就会变成
a 2 a 3 a 4 a 5 a 1 a_2~~~a_3~~~ a_4~~~a_5~~~a_1 a2 a3 a4 a5 a1
b 1 b 2 b 3 b 4 b 5 b_1~~~b_2~~~b_3~~~ b_4~~~b_5 b1 b2 b3 b4 b5
此时, a 5 a_5 a5有可能会大于 b 4 b_4 b4,导致题设不成立。
因此我们应该选择第一个 a i + 1 ≤ b i a_{i+1} \leq b_i ai+1≤bi 使得题设成立。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int T, n;
int a[200010], b[200010];
int main() {
cin >> T;
while (T--) {
cin >> n;
for (int i = 1; i <= n; i++)cin >> a[i];
for (int i = 1; i <= n; i++)cin >> b[i];
vector<int>vec;
b[0] = 1000000010;
for (int i = 1; i <= n; i++) {
int pos = lower_bound(b + 1, b + 1 + n, a[i]) - b;
cout << b[pos] - a[i] << " ";
if (a[i] > b[i - 1])vec.push_back(i - 1);
}
cout << "\n";
vec.push_back(n);
int t = 0;
for (int i = 1; i <= n; i++) {
if (i <= vec[t])cout << b[vec[t]] - a[i] << " ";
if (i == vec[t])t++;
}
cout << "\n";
}
return 0;
}
D. Maximum AND
题意
有序列 a , b , c a,b,c a,b,c,其中 c i = a i ⨁ b i c_i=a_i \bigoplus b_i ci=ai⨁bi,询问对序列 a , b a,b a,b 重新排列后,求 c 1 & c 2 & . . . . . c n c_1 {\&} c_2 {\&}.....c_n c1&c2&.....cn 的最大值。
题解
一些胡说八道:
憨憨原来写的是DFS,因为根据数据范围确实可行,类似于分治递归,判断某一个二进制位是否可取。
后来发现要改成BFS,然后MLE了QAQ,不过好像 dls 也是写的BFS。
在群里看 jls 讲他的做法,发现自己写的好复杂。
后面讲的就是 jls 的做法。
考虑异或以及与的性质,这道题本质上就是找到一个 x x x 使得 a & x = ( 取反 b ) & x a {\&} x = (取反~b) {\&} x a&x=(取反 b)&x。
由于需要找到最大的 x x x,我们可以贪心的从最高位开始考虑,若当前位满足条件,保留当前位的同时判断下一位是否符合要求。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int T, n;
ll ans = 0;
bool ok(vector<int>a,vector<int>b,int x) {
vector<int>c(n), d(n);
for (int i = 0; i < n; i++) {
c[i] = a[i] & x;
d[i] = ~b[i] & x;
}
sort(c.begin(), c.end());
sort(d.begin(), d.end());
return c == d;
}
int main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> T;
while (T--) {
cin >> n; ans = 0;
vector<int>a(n), b(n);
for (int i = 0; i < n; i++)cin >> a[i];
for (int i = 0; i < n; i++)cin >> b[i];
int ans = 0;
for (int i = 29; i >= 0; i--) {
if (ok(a, b, ans | (1 << i))) {
ans |= 1 << i;
}
}
cout << ans << "\n";
}
return 0;
}
本文精选了四道算法竞赛题目并提供了详细的题解,包括最小操作数染色问题、最短路径避开激光区域问题、序列变换求解最小最大值问题以及序列重组求最大AND值问题。


被折叠的 条评论
为什么被折叠?



