A:
题意:
您有一个大小为 2×2 的图像文件,由 4 个像素组成。 每个像素可以有 26 种不同颜色中的一种,用小写拉丁字母表示。
您想重新着色图像的某些像素,以便所有 4 个像素具有相同的颜色。 一步,你可以选择不超过两个相同颜色的像素,并将它们涂成其他颜色(如果你选择两个像素,两个像素应该涂成相同的颜色)。
为了实现目标,您必须采取的最少移动次数是多少?
输入
第一行包含一个整数 t (1≤t≤1000)——测试用例的数量。
每个测试用例由两行组成。 这些行中的每一行都包含两个拉丁字母的小写字母,没有任何分隔符,表示图像中的一行像素。
输出
对于每个测试用例,打印一个整数——为了使图像的所有 4 个像素具有相同的颜色,您必须进行的最少移动次数。
思路:
我们可以很快发现这个变化次数和位置无关,纯粹和这个图形有多少个不一样的颜色有关,然后因为2*2,直接暴力手模所有情况就可以了
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
map<char,int> mp;
signed main(){
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--){
char s[100][100];
cin>>(s[1]+1);
cin>>(s[2]+1);
mp.clear();
int cnt=0;
for(int i=1;i<=2;i++)
for(int j=1;j<=2;j++)
if(mp[s[i][j]]==0)
cnt++,mp[s[i][j]]=1;
if(cnt==2)
cout<<1<<endl;
else if(cnt==1)
cout<<0<<endl;
else if(cnt==3)
cout<<2<<endl;
else
cout<<3<<endl;
}
}
B
题意:
机器人放置在网格的左上角,网格由 n 行和 m 列组成,位于单元格 (1,1) 中。
在一个步骤中,它可以移动到一个单元格中,与当前单元格相邻:
(x,y)→(x,y+1);
(x,y)→(x+1,y);
(x,y)→(x,y−1);
(x,y)→(x−1,y)。
机器人不能在网格之外移动。
细胞 (sx,sy) 包含致命的激光。如果机器人进入某个距离激光小于或等于 d 的单元,它就会被蒸发掉。两个单元格 (x1,y1) 和 (x2,y2) 之间的距离为 |x1−x2|+|y1−y2|。
打印机器人在不蒸发或移出网格的情况下到达单元格 (n,m) 可以采取的最小步数。如果无法到达单元格 (n,m),则打印 -1。
激光既不在起始单元中,也不在结束单元中。起始单元到激光器的距离总是大于 d。
输入
第一行包含一个整数 t (1≤t≤104)——测试用例的数量。
每个测试用例的唯一一行包含五个整数 n,m,sx,sy,d (2≤n,m≤1000; 1≤sx≤n; 1≤sy≤m; 0≤d≤n+m) — 大小网格的大小、包含激光的单元格和激光的蒸发距离。
激光既不在起始单元中,也不在结束单元中 ((sx,sy)≠(1,1) 和 (sx,sy)≠(n,m))。起始单元 (1,1) 到激光 (|sx-1|+|sy-1|>d) 的距离总是大于 d。
输出
对于每个测试用例,打印一个整数。如果可以从 (1,1) 到达单元格 (n,m) 而不会蒸发或移出网格,则打印机器人到达它可以采取的最小步数。否则,打印 -1。
思路:
我们可以发现我们如果可以到n,m这个点,那么一定要么最上面和最右边的点没被封住,要么最下面和最左边的点没被封住,而且我们要保证终点不在激光范围内就一定可以走到,否则一定走不到。能走到的最短距离肯定是曼哈顿距离
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--){
int n,m,sx,sy,d;
cin>>n>>m>>sx>>sy>>d;
if(n-sx+m-sy<=d){
cout<<-1<<endl;
continue;
}
if(sx+d<n&&sy-d>1){
cout<<n+m-2<<endl;
continue;
}
if(sx-d>1&&sy+d<m){
cout<<n+m-2<<endl;
continue;
}
cout<<-1<<endl;
}
}
C:
题意:
给定一个数组 a1,a2,...,an,它按非降序排序。您决定执行以下步骤来创建数组 b1,b2,...,bn:
创建一个由 n 个任意非负整数组成的数组 d。
为每个 bi 设置 bi=ai+di。
以非降序对数组 b 进行排序。
您将得到结果数组 b。对于每个索引 i,计算您可以选择的最小和最大可能值是多少,以便获得给定的数组 b。
请注意,最小(最大)di-s 是相互独立的,即。 e.它们可以从不同的可能数组中获得 d.
输入
第一行包含单个整数 t (1≤t≤104) — 测试用例的数量。
每个测试用例的第一行包含一个整数 n (1≤n≤2⋅105) — 数组 a、b 和 d 的长度。
第二行包含 n 个整数 a1,a2,…,an (1≤ai≤109; ai≤ai+1) — 数组 a 以非降序排列。
第三行包含 n 个整数 b1,b2,…,bn (1≤bi≤109; bi≤bi+1) — 非降序数组 b。
对输入的附加限制:
至少有一种方法可以通过选择由非负整数组成的数组 d 从 a 中获取数组 b;
n 之和不超过 2⋅105。
输出
对于每个测试用例,打印两行。在第一行,打印 n 个整数 dmin1,dmin2,…,dminn,其中 dmini 是可以添加到 ai 的最小可能值。
其次,打印 n 个整数 dmax1,dmax2,…,dmaxn,其中 dmaxi 是您可以添加到 ai 的最大可能值。
所有 dmini 和 dmaxi 值都是相互独立的。换句话说,对于每个 i,dmini 只是所有可能的 di 值中的最小值。
思路:
我们可以发现最小可能就是这个数字可以到达的最小的不小于他本身的b[i],那么我们用二分进行查找就好了。我们还发现一旦这个数字可以到达这个最小的不小于他本身的b[i]时,我们所寻求的这个i也可以到达这个数字。那么我们可以到达这个数字就代表着我们也可以用来替代这个数字能到达的最远的地方。
因此我们可以做一个初始化,每个数字开始能到达的最远距离是它自己,然后从后往前枚举能跳到的离1最近的距离p,那么这个距离p也可以跳到当前这个距离i,那么这个p取最远的距离就好了。因为我们先前已经按照大小排序了一下。
然后我们从1到n再进行取最大值一下,因为能跳到i的一定能跳到i+1,所以每一个i和后面的i-1取一下max就好了
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[200005];
int b[200005];
int c[200005];
int d[200005];
int n;
signed main(){
ios::sync_with_stdio(false);
int t;
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];
sort(a+1,a+1+n);
sort(b+1,b+1+n);
for(int i=1;i<=n;i++)
d[i]=i;
for(int i=n;i>=1;i--){
int p=lower_bound(b+1,b+1+n,a[i])-b;
c[i]=b[p]-a[i];
d[p]=max(d[p],d[i]);
}
for(int i=1;i<=n;i++){
d[i]=max(d[i],d[i-1]);
}
for(int i=1;i<=n;i++)
cout<<c[i]<<" ";
cout<<endl;
for(int i=1;i<=n;i++)
cout<<b[d[i]]-a[i]<<" ";
cout<<endl;
}
}
D:
题意:
给定两个数组 a 和 b,每个数组由 n 个整数组成。
让我们定义一个函数 f(a,b) 如下:
让我们定义一个大小为 n 的数组 c,其中 ci=ai⊕bi(⊕ 表示按位异或);
该函数的值是 c1&c2&⋯&cn(即整个数组 c 的按位与)。
如果您可以以任意方式对数组 b 重新排序(保留初始顺序也是一种选择),则找到函数 f(a,b) 的最大值。
输入
第一行包含一个整数 t (1≤t≤104)——测试用例的数量。
每个测试用例的第一行包含一个整数 n (1≤n≤105) — 数组 a 和 b 的大小。
第二行包含 n 个整数 a1,a2,…,an (0≤ai<230)。
第三行包含 n 个整数 b1,b2,…,bn (0≤bi<230)。
所有测试用例的 n 总和不超过 105。
输出
对于每个测试用例,打印一个整数——如果您可以以任意方式对数组 b 重新排序,则为函数 f(a,b) 的最大值。
思路:
因为要找到最大值,而且我们发现b重新排列等于c也可以乱排列,只要保证一个c对应一个b就好了。那么我们要求出最大值的话,可以想出按位贪心的方法。但是要怎么按位贪心呢,我们从最高位开始遍历,如果说这一位可以拥有1的话,那肯定比当前位没1后面有1大,所以我们要在维护前面有1的同时使得当前位也有1.那么怎么做才能让一位产生1呢。
那肯定是上面的a[i]当前这一位是1下面的b[i]当前这一位是0或者上面的a[i]当前这一位是0下面的b[i]这一位是1.那么我们还得维护一下前面的要让他在满足前面成立的情况下照顾一下这一位,那么我们发现这个其实就是要维护假设当前这一位为1和加上前缀的1,发现两个前i位本身异或起来就是那个数字的话,两个数字就是互补,一旦发现每一个数字都存在下面的一个数字和它互补的话,那么这一位就可以成立,否则这一位不能够成立。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[200005];
int b[200005];
signed main(){
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
cin>>b[i];
int ans=0;
map<int,int> mp1,mp2;
for(int i=32;i>=0;i--){
ans|=(1ll<<i);
mp1.clear();
mp2.clear();
for(int j=1;j<=n;j++)
mp1[a[j]&ans]++,mp2[b[j]&ans]++;
for(auto p:mp1){
int u=p.first;
if(mp2[u^ans]!=p.second){
ans-=(1ll<<i);
break;
}
}
}
cout<<ans<<endl;
}
}