A. Image
题意:给定一个2*2的像素文件,每个像素可以是26种不同的颜色之一,用26个小写字母表示,每次操作你可以选择至多两个相同的像素变成另外一种颜色,问最少需要几次操作使得4个像素颜色一样。
题解
这个题只需要统计颜色的种类数,答案就是种类数减一
代码实现
#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <iomanip>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <math.h>
#define ll long long
#define fst ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
int t;
char a, b, c, d;
int main(){
cin >> t;
while(t--){
set<char> st;
cin >> a >> b >> c >> d;
st.insert(a);
st.insert(b);
st.insert(c);
st.insert(d);
cout << st.size() - 1 << "\n";
}
return 0;
}
B. Deadly Laser
题意:给定一个n行m列的矩阵,一个机器人位于(1,1),在(sx,sy)处有一个激光,当机器人位于和激光的距离小于等于d的点时会被消灭(两点(x1,y1)和(x2,y2)之间的距离定义为|x1 - x2| + |y1 - y2|),机器人要到(n,m)点处,期间不能越过边界,现在问机器人能否到达终点,如果能,输出最小步数,如果不能,输出-1
题解
其实这个题目只需要解决能否到达终点的问题,因为如果能到达,不管怎么走步数都是n + m - 2
那我们现在考虑一下在什么情况下机器人无法到达终点,由距离的定义可知激光的杀伤范围其实是一个矩形,而真正影响机器人路线的只有矩形的四个顶点,也就是激光向上下左右最大能攻击到的距离,画图分析一下可知当激光上下,左右,左上(围住起点)或右下(围住终点)触碰到边界,那么机器人就无法到达终点,其他情况机器人都能通过绕路避开激光的攻击
代码实现
#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <iomanip>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <math.h>
#define ll long long
#define fst ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
int t, n, m, sx, sy, d;
int main(){
cin >> t;
while(t--){
cin >> n >> m >> sx >> sy >> d;
if((sx - 1 <= d && sy - 1 <= d) ||( n - sx <= d && m - sy <= d) || (sx - 1 <= d && n - sx <= d) || (sy - 1 <= d && m - sy <= d)) cout << -1 << "\n";
else cout << n + m - 2 << "\n";
}
return 0;
}
C. Min-Max Array Transformation
题意:分别给出两个长度为n的非递减序列a和b,其中b序列是由a序列加上一个非递减的长度为n的d序列,然后按非递减的顺序排列得到,现在问d序列每一位的最小值和最大值
题解
首先看最小值的情况,我们肯定尽量让每一位b最接近a,这样减出来的d最小,那我们的策略就是对于每一个a[i],在b序列中找到第一个大于等于a[i]的b[j],那么d[i]min = b[j] - a[i],可以用二分查找实现
然后是最大值的情况,最直接的想法肯定是拿b序列中最大的数减去每一位a[i],但是这样安排可能会导致d序列不满足非递减的条件,比如下面的例子
a:1,2,3,5
b:2,3,4,5
如果直接让a[1]对应b[4],那么就会变成
a:2,3,5,1
b:2,3,4,5
你会发现a[3] > b[3],那么d[3] = -1,而d是个非负数列,所以无法满足
观察一下,对a[i]进行匹配的过程,实际上相当于将a[i]往后移,找到一个尽可能靠后的位置,这样所得的d[i]最大,这个过程中a[i]所移至的位置之前的a也会相应向前移一位,那么这时候就需要判断对应的b是否满足条件了,也就是判断是否a[i + 1] <= b[i],从i + 1开始判断,第一个不满足条件的b的位置pos即a[i]最远能移至的位置,所以答案就是b[pos] - a[i]
一开始找第一个不满足条件的位置,直接暴力从i + 1开始找,然后果不其然t了,然后发现能优化,因为不管哪个i,判断的对象从始至终都是这个序列,如果这次找到了pos这个位置,说明pos之前都满足a[i + 1] <= b[i],那么下一次pos之前的也就不用再判断了
代码实现
#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <iomanip>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <math.h>
#define ll long long
#define fst ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N = 2e5 + 50;
int t, n;
int a[N], b[N];
int main(){
fst;
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];
for(int i = 1; i <= n; i++){
int pos = lower_bound(b + 1, b + 1 + n, a[i]) - b;
cout << b[pos] - a[i] << " ";
}
cout << "\n";
int j = 1;
for(int i = 1; i <= n; i++){
j = max(j, i);
while(j < n && a[j + 1] <= b[j]) j++;
cout << b[j] - a[i] << " ";
}
cout << "\n";
}
return 0;
}
D. Maximum AND
题意:给定两个包含n个数的序列a和b,定义一个序列c,它的每一位c[i] = a[i] ^ b[i],在b序列能重新排列的条件下,问c1 & c2 & … & cn的最大值
题解
要使c1 & c2 & … & cn的结果尽量大,肯定要尽量多的出现1,而某一位为1当且仅当所有的c的这一位都为1,这就要求每一个a[i]和b[i]在当前位为一个0一个1,如果能满足,那这一位就可以出现1,否则不可以,因为要求最大值,那么根据贪心的策略,我们肯定先保证较大的位数,所以在枚举每一位时从大到小进行枚举,对于每一位,我们先让答案加上这一位然后去判断是否满足条件,如果满足,就加上,否则,就减去
判断是否满足条件可以考虑让b取反,这样就不需要管哪个是0哪个是1了,a和取反的b分别&x得到c和d,将c和d分别排序,然后比较是否相等即可
代码实现
#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <iomanip>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <math.h>
#define ll long long
#define fst ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N = 1e5 + 50;
int t, n;
int a[N], b[N];
bool check(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(){
fst;
cin >> t;
while(t--){
cin >> 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(check(ans + (1 << i))) ans += 1 << i;
}
cout << ans << "\n";
}
return 0;
}