牛客练习赛101D:推理小丑

牛客练习赛101D:推理小丑

链接:https://ac.nowcoder.com/acm/contest/11247/C
来源:牛客网

题目描述

给出一个长度为 \(n\) 的序列 \(a\) ,满足 \(a_i<a_{i+1}(i\in[1,n-1])\)

要求一个最小的 \(x\) 满足 \(a_i\ and\ x<a_{i+1}\ and\ x\ (i\in[1,n-1])\)

其中 \(and\) 操作表示 按位与 ,如果你不了解定义可以自行查找资料或阅读下列定义:

将两个整数作为二进制数,对二进制表示中的每一位逐一运算,只有对应的两个二进位都为 \(1\) 时,结果位才为 \(1\)

输入描述:

第一行给出一个正整数 \(n\)\((1\leq n\leq 10^5)\) 。接下来一行给出 \(n\) 个非负整数表示 \((0\leq a_i<2^{31})\)

输出描述:

输出一行一个非负整数表示满足条件最小的 \(x\)

输入

5
0 2 5 114 514

输出

534-

说明

对于样例中,所有的 \(a_i\ and\ x\) 分别是:\(0,2,4,18,514\) 。可以证明,不存在更小的 $x $满足条件。

题目解析

考虑从高位往低位贪心,考虑第 i 位是否必须填 \(1\)

我们先默认 \(i\) 位填 \(0\) ,再从大到小枚举一个 \(j<i\) ,此时因为我们如果第 \(j\) 位可以为 \(1\) 就必须填 \(1\) ,这样一定是对的,因为每个能够填上去的 \(j\) 都可以去分割序列中的一些段(也就是固定一些位置的 \(a_x<a_{x+1}\))。
这样最后看是否能找到一个合法的解就可以确定第 \(i\) 位是否必须填 \(1\) 了。
时间复杂度:\(O(n\log ^2 a)\)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int n,a[N];
int main()
{
    scanf("%d",&n);
    if(n<1||n>1e5)return -1;
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<n;i++) 
        if(a[i]>=a[i+1])return -1;
    int ans=0;
    for(int j=30;j>=0;j--){
        int now=ans;
        for(int k=j-1;k>=0;k--){
            bool flag=0;now|=1<<k;
            for(int i=1;i<n;i++)
                if((a[i]&now)>(a[i+1]&now))
                {flag=1;break;}
            if(flag)now^=1<<k;
        }
        bool flag=0;
        for(int i=1;i<n;i++)
            if((a[i]&now)>=(a[i+1]&now))
            {flag=1;break;}
        if(flag)ans|=(1<<j);
    }
    for(int i=1;i<n;i++)
        if((a[i]&ans)>=(a[i+1]&ans))
            return -1;
    printf("%d\n",ans);
    return 0;
}

posted @ 2022-06-27 14:45  seekerHeron  阅读(106)  评论(0)    收藏  举报