Educational Codeforces Round 134 (Rated for Div. 2) A-D

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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值