zoukankan      html  css  js  c++  java
  • codeforces 165E Compatible Numbers

    昨天看到一道好题,现与大家分享一下。

    http://codeforces.com/contest/165/problem/E

    题目大意:给一个序列a1~an(n<=1000000),问对于每一个ai来说,是否存在一个数x使得 ai&x==0且x是序列a 中的元素。ai的范围是(1<=ai<=4000000)。

    思路:对于一个数,比如说53,其二进制表示为 110101,取它的反,即为001010,我们知道,若一个数x使得x&53==0,则x的二进制一定是这样一个形式:00?0?0(其中?表示可以为0也可以为1)。那么我们设这样一个数组 vis[x]={0,1},表示x是否可以由序列a中的元素,将其二进制中的若干0改为1后得到。比如说如果a中存在53(110101),那么我们可以得到 (111101)61,(110111)55,(111111)63,则vis[53]=vis[55]=vis[61]=vis[63]=1,这个数列我们可以先预处理一遍得到,因为ai最大为4000000,所以预处理的复杂度为 (1<<K)*K(其中K为序列中最大的数其二进制表示的长度,最大为22)。那么有了这个数组,我们就可以求出对于每一个数的答案了,首先,我们要求ai对应的数,我们首先取反,得到tmp,此时若vis[tmp]==0,我们可以肯定序列a中不存在与ai与操作后等于0的数,直接输出-1,否则,我们可以知道一定存在一个数,那么我们怎么求这个数呢?

    具体步骤如下:

    我们首先设答案ans为0,我们枚举tmp的每一位,如果遇到1,则我们把这一位设为0后,再看tmp是否存在,如果不存在,说明我们要找的那个数这一位上一定为1,则我们将ans的这一位赋值为1,然后将tmp恢复后继续遍历,如果存在,说明我们要找的数这一位可以为0(注意不是一定),则我们继续遍历即可。如果遇到0,直接继续遍历,因为我们要找的数这一位上一定为0。遍历完之后,ans的值即为答案,输出即可。这一步的时间复杂度为O(n*K),(K由上面定义),可以在规定的时间内跑完。具体代码如下:

    #include <iostream>
    #include <string.h>
    #include <stdio.h>
    #include <algorithm>
    #define ll long long
    #define maxn 4500000
    using namespace std;
    int getlen(int x)
    {
        int sum=0;
        while(x)
        {
            sum++;
            x/=2;
        }
        return sum;
    }
    int vis[maxn];
    int a[1000010];
    int main()
    {
        //freopen("dd.txt","r",stdin);
        memset(vis,0,sizeof(vis));
        int n,max=0,i,j;
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if(max<a[i])
            max=a[i];
            vis[a[i]]=1;
        }
        if(n==1)
       {
           printf("-1\n");
           return 0;
       }
    
        int len=getlen(max);
        int limit=(1<<len)-1;
        for(i=0;i<=limit;i++)
        {
            if(!vis[i])
            continue;
            for(j=0;j<len;j++)
            {
                if(((1<<j)&i)==0)
                {
                    vis[i^(1<<j)]=1;
                }
            }
        }
        for(i=1;i<=n;i++)
        {
            int tmp=limit-a[i];
            //printf("%d\n",tmp);
            if(!vis[tmp])
            printf("-1 ");
            else
            {
                int ans=0;
                for(j=0;j<len;j++)
                {
                    if(tmp&(1<<j))
                    {
                        if(vis[tmp^(1<<j)])
                        tmp^=(1<<j);
                        else
                        {
                            ans+=1<<j;
                        }
                    }
                }
                printf("%d ",ans);
            }
        }
        printf("\n");
        return 0;
    }


     

  • 相关阅读:
    python 包管理工具 pip 的配置
    Python 变量作用域 LEGB (下)—— Enclosing function locals
    Python 变量作用域 LEGB (上)—— Local,Global,Builtin
    2020 Java 面试题 小结 (答案慢慢补上,有错误请指出)
    mysql 根据日期(date)做年,月,日分组统计查询
    jvm指令
    正则表达式 分割地址 获取省市区详细地址
    .Net 异常记录
    WCF设计服务协议(一)
    plsql ORA-01789:查询块具有不正确的结果列数
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/3000809.html
Copyright © 2011-2022 走看看