Educational Codeforces Round 134 (Rated for Div. 2)(A~D)(模拟、构造、二进制异或)

A. Image

模拟

#include<bits/stdc++.h>
using namespace std;
map<int,int>mp;
int main()
{
    int T;cin>>T;
    while(T--){
        mp.clear();char a,b,c,d;cin>>a>>b>>c>>d;
        mp[a]++;mp[b]++;mp[c]++;mp[d]++;
        int sum=0;int r=4;
        for (auto i:mp){
            if(i.second==1&&r!=1){sum++;r--;}
            if(i.second==2&&r!=2){sum++;r-=2;}
        }
        cout<<sum<<endl;
    }
    return 0;
}

题解是用set做的,更简单

#include<bits/stdc++.h>
using namespace std;
set<char>mp;
int main()
{
    int T;cin>>T;
    while(T--){
        mp.clear();
        char a,b,c,d;cin>>a>>b>>c>>d;
        mp.insert(a);mp.insert(b);mp.insert(c);mp.insert(d);
        cout<<(int)mp.size()-1<<endl;
    }
    return 0;
}

B. Deadly Laser

思路:首先无论怎么走,最小步数都是n+m-2,所以就是看激光覆盖的范围阻挡了路

有4种阻挡方式

1.拦住左下角        2.拦住右上角        3.拦住竖的        4.拦住横的

代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;cin>>T;
    while(T--){
        int n,m,sx,sy,d;cin>>n>>m>>sx>>sy>>d;
        if(m-sy<=d&&n-sx<=d||sy-1<=d&&sx-1<=d||sy-1<=d&&m-sy<=d||sx-1<=d&&n-sx<=d)
             cout<<-1<<'\n';
        else cout<<(n+m-2)<<'\n';
    }
    return 0;
}

C. Min-Max Array Transformation

注意点:数据范围是2e5,数组开小了会TLE

思路:

首先找最小的数组很好找,只要找恰好等于它的数字就可以了;

找最大数的话,看样例的规律,从n-1到0的话,如果 a[i] 大于b[i-1],这代表b[i-1]不可能是a[i]以及之前的数的和,所以从b[i-1]开始作为新的开头;否则因为前面b[i]都是大于a[i]的,没有限死,所以都可以选最大的

#include<bits/stdc++.h>
using namespace std;
int a[200005],b[200005],d[200005];
int main()
{
    ios::sync_with_stdio(0);
    int T;cin>>T;
    while(T--){
        int n;cin>>n;
        int minn=999999999;int maxx=0;
        for(int i=0;i<n;i++)cin>>a[i];for(int i=0;i<n;i++)cin>>b[i];
        int l=0;
        for(int i=0;i<n;i++){while(b[l]<a[i])l++;cout<<b[l]-a[i]<<" ";}
        cout<<'\n';
        l=n-1;
        for(int i=n-1;i>=0;i--){d[i]=b[l]-a[i];if(a[i]>b[i-1])l=i-1;}
        for(int i=0;i<n;i++)cout<<d[i]<<" ";cout<<'\n';
    }
    return 0;
}

从前往后找的道理差不多

#include<bits/stdc++.h>
using namespace std;
int a[200005],b[200005];
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    int T;cin>>T;
    while(T--){
        int n;cin>>n;
        for(int i=0;i<n;i++)cin>>a[i];
        for(int i=0;i<n;i++)cin>>b[i];
        int l=0;
        for(int i=0;i<n;i++){while(b[l]<a[i])l++;cout<<b[l]-a[i]<<" ";}
        cout<<'\n';l=0;
        for(int i=0;i<n;i++){
            l=max(l,i);while(a[l+1]<=b[l]&&l+1<n)l++;cout<<b[l]-a[i]<<" ";
        }
        cout<<'\n';
    }
    return 0;
}

D. Maximum AND

题意:有数列a和b,数列c是通过a异或b得出的,最后的value是数组c的与运算,求最大的value

思路:

方法一:

已知最后的value的最高位一定是c数组的每个都有的1的那个位置

每个都有1的位置是由a数组的1和b数组的0做成的(或者a数组的0和b数组的0做成的)

那么可以设一个数x,x与上每一个a[i],其结果cc是只有x上有1的位数a[i]同时有1的位数才能显示出来

x与上每一个(取反的b[i]),其结果dd是只有x上有1的位数和(取反的b[i])同时有1的位数才能显示出来

如果cc和dd能过一一相等,代表了a[i]的1和b[i]的0能够一一对应(同时也是a[i]的0和b[i]的1一一对应了)

所以check时只要判断cc和dd是否相等就可以了

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[100005];int b[100005];int n;
int c[100005];int d[100005];
bool check(int x){
    for(int i=1;i<=n;i++)c[i]=a[i]&x;
    for(int i=1;i<=n;i++)d[i]=(~b[i])&x;
    sort(c+1,c+1+n);sort(d+1,d+1+n);
    for(int i=1;i<=n;i++){
        if(c[i]!=d[i])return 0;
    }
    return 1;
}
signed main()
{
    int T;cin>>T;
    while(T--){
        int coun=0;cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        for(int i=1;i<=n;i++)cin>>b[i];
        int res=0;
        for(int i=31;i>=0;i--){
            if(check(res|(1<<i)))res=res|((1<<i));
        }
        cout<<res<<'\n';
    }
    return 0;
}

方法二(并查集)

如果某一位a的1部分和b的0部分配对,如果个数不对就continue

如果对了的话就从那一部分再把a的1部分和b的0部分配对,如果个数不对接着continue

但我还没看……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值