Bitwise Or vs LCM(思维,lcm,或运算)

题意:

给定长度为 n n n 的数列 a a a,问是否存在一个二元组 ( i , j ) (i, j) (i,j) 满足: a i ∣ a j ≥ l c m ( a i , a j ) ai | aj ≥ lcm(ai, aj) aiajlcm(ai,aj)
如果存在输出任一组,否则输出 -1。
1 ≤ n ≤ 2 × 1 0 5 , 1 ≤ a i ≤ 1 0 6 1\le n \le 2 \times 10 ^ 5,1 \le a_i \le 10 ^ 6 1n2×1051ai106

思路:

首先:讨论对于 取或(|) 操作 x|y 的范围:

  • 因为二进制中的或操作如果两个数有一个位置为 1,那么其或值给位置就为 1,所以 x|y 肯定大于等于 max(x, y);
  • 两个数取或,其或值的二进制最高位1肯定和 max(x, y) 的最高位1位于相同位置,而2max(x,y) 的最高位 1 在 max(x,y) 的最高位 1 左一位,所以 2max(x,y) 肯定要大于 x|y。

所以:2max(x,y) > x|y ≥ max(x,y)

那么:
对于两个数 x,y,不妨设 x≤y,那么就有两种情况:

  • lcm(x,y) = y
    此时,x|y≥y,于是 x|y ≥ lcm(x,y),满足。
  • lcm(x,y) ≠ y
    那么由 lcm(x,y) ≥ 2y,而 x|y < y,则 x|y 肯定小于 lcm(x,y), 这种情况肯定不满足。

所以满足条件的情况只有:lcm(x,y) = y,即一个数为另一个数的倍数。

那么题目就转化为:
找出一对位置 ( i , j ) (i,j) (i,j) 满足一个位置上的数为另一个数的倍数。
所以遍历每个数的倍数,判断其是否出现过。整体复杂度O(nlogn)。

Code:

map<int,int> mp;

const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N];

int main(){
	cin>>n;
	
	int maxa=0;
	for(int i=1;i<=n;i++){
		cin>>a[i], maxa=max(maxa, a[i]);
		if(!mp[a[i]]) mp[a[i]]=i;
		else
		{
			cout<<min(i, mp[a[i]])<<" "<<max(i, mp[a[i]]);
			return 0;
		}
	}
	
	for(int i=1;i<=n;i++)
	{
		int x=a[i];
		for(int j=2*x;j<=maxa;j+=x)
		{
			if(mp[j]){
				cout<<min(i, mp[j])<<" "<<max(i, mp[j]);
				return 0;
			}
		}
	}
	cout<<-1;
	
	return 0;
}

那么这道题就是一个思维题,就看能不能把题意转化过来。
学到了两个知识点:

  • 2 m a x ( x , y ) > x ∣ y ≥ m a x ( x , y ) 2max(x,y) > x|y ≥ max(x,y) 2max(x,y)>xymax(x,y);
  • 设 x≤y,如果y不是x的倍数的话: l c m ( x , y ) ≥ 2 m a x ( x , y ) lcm(x,y) ≥ 2max(x,y) lcm(x,y)2max(x,y)

逐渐积累吧!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值