牛客练习赛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;
}

浙公网安备 33010602011771号