Educational Codeforces Round 134 (Rated for Div. 2)

目录

A. Image

B. Deadly Laser

C. Min-Max Array Transformation

D. Maximum AND


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;
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值