目录
C. Min-Max Array Transformation
A. Image
题意:四个格子,每个格子一个小写字母,每次可以选择至多两个相同字母进行变换,问让所有字母变成一样的,最少几步.
思路:用set存字母,再用set的size-1即可.因为当只有一种字母的时候可知为0,有两种的所有情况无非就是2+2和3+1,都只需要一步即可,三种字母的情况就是2+1+1,需要两步,四种字母情况是1+1+1+1需要三步.
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =5e5+10,mod=998244353;
string a,a1;
set<char>se;
void solve()
{
se.clear();
cin>>a>>a1;
a+=a1;
for(int i=0;i<a.size();i++)
se.insert(a[i]);
cout<<se.size()-1<<endl;
return ;
}
signed main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
int t;
cin>>t;
while(t--)
solve();
return 0;
}
B. Deadly Laser
题意:问从左上角(1,1)到右下角(n,m)需要多少步.不同的是有一个激光炮台可以把距离该炮台曼哈顿距离为k的路上的人都摧毁.问能否到达,能到达需要几步.
思路:能到达的话肯定是n+m-2步,考虑不能到达的情况.我们最坏的情况就是贴着边走,要么上面的边加右边的,要么左边的加下面的,只需要考虑从炮台延伸出两道墙看你能否堵住上述的两种情况即可.一共有四种堵法.
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =5e5+10,mod=998244353;
void solve()
{
int n,m,x,y,d;
cin>>n>>m>>x>>y>>d;
int lx=x-d,dx=x+d;
int ly=y-d,dy=y+d;
if(lx<=1&&dx>=n||ly<=1&&dy>=m||ly<=1&&lx<=1||dx>=n&&dy>=m)
{
cout<<"-1"<<endl;
return ;
}
cout<<n+m-2<<endl;
}
signed main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
int t;
cin>>t;
while(t--)
solve();
return 0;
}
C. Min-Max Array Transformation
题意:给你一个非递减数组a.对于每个元素ai加上一个di,得到新的数组bi(不一定非递减),然后按照非递减的顺序排序,求在合法构造的情况下a和b数组相匹配,每一个的di的最大值和最小值.
思路:最小值好求,只需要在b数组中找到第一个大于a[i]的元素b[j],用b[j]-a[i]即为当前这位的di的最小值.最大值就稍微难一点.我们可知最后一位的对大致是固定的,那么就倒着往前遍历.我们记录当前能和a数组匹配的最大的b数组中元素下标是p.当a[i]>b[i-1]的时候,那么i到p区间内合法最大值都是b[p]-a[i].此时再往前会因为a[i]>b[i-1]而导致规则不成立,直接把p更新为i-1,在继续匹配即可.
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =2e5+10,mod=998244353;
int a[N],b[N],c[N],d[N];
void solve()
{
int n,l,r,mid;
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++)
{
l=1,r=n;
while(l<r)
{
mid=(l+r)/2;
if(b[mid]>=a[i])
r=mid;
else
l=mid+1;
}
cout<<b[l]-a[i]<<" ";
}
cout<<endl;
int p=n;
for(int i=n;i>=1;i--)
{
c[i]=b[p]-a[i];
if(a[i]>b[i-1])
p=i-1;
}
for(int i=1;i<=n;i++)
cout<<c[i]<<" ";
cout<<endl;
return ;
}
signed main()
{
int t;
cin>>t;
while(t--)
solve();
return 0;
}
D. Maximum AND(位运算妙妙题)
题意:给你两个数组a,b.b数组是可以随意排列,ci=ai^bi,ans=c1&c2&c3&c4...cn,求ans的最大值.
思路:贪心枚举高位,如果a中0的数量和b中1的数量相等,就判断ans的前面数位置为1的情况是否成立,成立该位就置为1.
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =1e5+10,mod=998244353;
int a[N],b[N];
void solve()
{
int n,ans=0;
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=29;i>=0;i--)
{
map<int,int>ma;
ans^=(1<<i);
for(int i=1;i<=n;i++)
{
ma[a[i]&ans]++;
ma[(~b[i])&ans]--;
}
//这里将a元素和b元素取反&ans就可以达到两个效果:1.a数组元素中的当前数位上0
//和b组元素数位上1的数量相等 2.前面匹配过数位的a,b满足条件.因为ans包含了以前
//置为1的数位.当当前状态符合条件时才会++,--抵消
int f=0;
for(int i=1;i<=n;i++)
{
if(ma[a[i]&ans])
{
f=1;
break;
}
}
if(f)//如果没有抵消就说明不合法,f=1,此位不为1
ans^=(1<<i);
}
cout<<ans<<endl;
return ;
}
signed main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
int t;
cin>>t;
while(t--)
solve();
return 0;
}