赛后补题:Codeforces Round #843 (Div. 2) 1775C. Interesting Sequence

传送门:CF

题目描述:

Petya and his friend, robot Petya++, like to solve exciting math problems.
One day Petya++ came up with the numbers n and x and wrote the following equality on the board:
n & (n+1) & … & m=x,
where & denotes the bitwise AND operation. Then he suggested his friend Petya find such a minimal 
m (m≥n) that the equality on the board holds.
Unfortunately, Petya couldn't solve this problem in his head and decided to ask for computer help. He 
quickly wrote a program and found the answer.
Can you solve this difficult problem?
输入:
5
10 8
10 10
10 42
20 16
1000000000000000000 0
输出:
12
10
-1
24
1152921504606846976

赛场上的做法假了,一直挂在一个点上,感觉还是自己前面的题做的太慢了,导致这道题时间并不充裕,然后慌起来之后脑子也比较混乱.赛后感觉这道题也并不是很难…

主要思路:

  1. 首先我们把玩一下我们的题目,我们会发现原来的式子 n & ( n + 1 ) & … & m = x n\&(n+1)\& … \&m=x n&(n+1)&&m=x有一个比较显然的性质,那就是我们 & \& &的越多,我们的式子显然是越小的.因为我们的之前的二进制1会因为后面的0变成0,但是并不会有新的1出现,所以肯定是越变越小的
  2. 所以一个比较简单的枚举区间就出来了,那肯定就是一直进行 & \& &运算,然后到式子的值比x还要小的时候如果还没有和x相等过的话,肯定就不可能再相等了,直接输出-1即可,但是直接一个一个枚举肯定是不行的,必超时,所以我们需要进行一点点优化.
  3. 我们把玩一下我们的二进制式子和我们的 & \& &运算.我们会发现因为二进制1后面的0存在,所以我们的二进制位最后一个1后面的数字再变化就没有意义,并不会改变我们的所有式子,讲起来可能比较抽象,举一个简单的栗子:
1010101000

比如上面的这个二进制数字,假设当前我们的式子最终的数字是这个,那么此时我们给他 + 1 , + 2 , + 3 +1,+2,+3 +1,+2,+3等等都是没有任何意义的,因为加的数字只贡献最后一个1后面的0的数字,和我们的0与起来依旧是0.那么加多少才有意义呢,我们会发现需要一直加到(1000)这个数字才会发生改变,而这个数字恰好是我们最后一个1形成的二进制数!!

至于如何找到我们的二进制位中的最后一个1,我们有一个比较模板的写法,称之为 l o w b i t 函数 lowbit函数 lowbit函数,这个函数在树状数组中会使用到,网上博客介绍得到也十分详细,此处就不再赘述了

下面是具体的代码部分:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define int long long 
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int t;
int n,x;
int lowbit(int x) {return x&(~x+1);}
signed main() {
	t=read();
	while(t--) {
		n=read();x=read();
		if(x>n) {
			printf("-1\n");continue;
		}
		if(x==n) {
			printf("%lld\n",x);continue;
		}
		int flag=0;
		while(n>=x) {
			int temp=n+lowbit(n);
			n&=temp;
			if(n==x) {
				printf("%lld\n",temp);
				flag=1;
				break;
			}
		}
		if(flag==0) printf("-1\n");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值