• CodeForces


    题目链接:

    https://vjudge.net/problem/1735275/origin

    基本思路:

    本题思路比较简单,首先,我们知道 a & x = b, b & x = b; 所以,一个数通过与运算改变只能改变一次!

    所以,这里就有一种暴力的写法,三次for循环,时间复杂度是O(3n)。

    第一次,从1到n遍历一遍,计算各个元素出现的次数,如果大于等于2,则输出0,结束。

    第二次,从1到n遍历,如果存在 vis[ a[i]&k ] >= 2 并且 与k与运算后的值与之前的不同,即a[i] != a[i]&k,于是输出1,结束。

    第三次,从1到n遍历,对a[i]&k的元素加一,即vis[ a[i]&k ]++,如果存在vis[ a[i]&k ] >= 2 && (a[i]&k) != a[i],则输出2,结束。

    AC代码如下:

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    const int MX = 1e5+10;
    int a[MX], vis[MX];
    
    int main()
    {
        int n, k;
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        for(int i = 1; i <= n; ++i)
        {
            vis[ a[i] ]++; // 第一次统计一下元素的个数
            if(vis[ a[i] ] >= 2)
            {
                printf("0
    ");
                return 0;
            }
        }
        for(int i = 1; i <= n; ++i)
        {
            // 一次与运算有值并且这个与运算得到的结果和之前的值不同时则说明操作一次即可
            if(vis[ a[i]&k ] == 1 && a[i] != (a[i]&k)) // 注意要加括号!
            {
                printf("1
    ");
                return 0;
            }
        }
        for(int i = 1; i <= n; ++i)
        {
            vis[ a[i]&k ]++; // 操作两次时直接遍历一遍
            if(vis[ a[i]&k ] >= 2 && a[i] != (a[i]&k)) // 这里要注意一下与运算重复的现象!
            {
                printf("2
    ");
                return 0;
            }
        }
        printf("-1
    ");
        return 0;
    }
    View Code

    第二种解法用到了flag标记。

    第一种情况,未进行与运算就存在,则输出0。

    第二种情况, 进行了一次与运算与之前元素重复,或者输入元素与之前与运算元素重复,则与对比1求最小值。

    第三种情况, 与运算结果与之前与运算结果相同则与2对比得最小值。

    下面是AC代码:

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    const int INF = 0x3f3f3f3f;
    const int MX = 1e5+10;
    bool flag[MX][3]; // 一个数有两种状态!
    
    int main()
    {
        int ans = INF;
        int n, k;
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; ++i)
        {
            int x;
            scanf("%d", &x);
            int y = x&k;
            if(flag[x][0]) // 未进行与运算就存在,则输出0
            {
                ans = min(ans, 0);
            }
            else if(flag[y][0] || flag[x][1]) //进行了一次与运算与之前元素重复,或者输入元素与之前与运算元素重复,则与对比1求最小值
            {
                ans = min(ans, 1);
            }
            else if(flag[y][1]) // 与运算结果与之前与运算结果相同则与2对比得最小值
            {
                ans = min(ans, 2);
            }
            flag[x][0] = true;
            flag[y][1] = true;
        }
        if(ans == INF) printf("-1
    "); // 都不符合作则输出-1
        else printf("%d
    ", ans);
        return 0;
    }
    View Code

    如有疑问,欢迎评论指出!

    化繁为简 大巧不工
  • 相关阅读:
    VBA 如何检测一个中文字符串是否包含在另一个字符串中
    RFC2119 规范内容
    Android 解读Event和Main Log
    为知笔记发布博客地址
    理解 Android Build 系统
    皮肤病
    关于Android中50M+的文本入库处理细节
    at java.lang.AbstractStringBuilder.toString
    java.lang.AbstractStringBuilder.enlargeBuffer
    关于手机定位轨迹的算法逻辑
  • 原文地址:https://www.cnblogs.com/mpeter/p/10299632.html
Copyright © 2020-2023  润新知