题意:
给定长度为
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)
ai∣aj≥lcm(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
1≤n≤2×105,1≤ai≤106
思路:
首先:讨论对于 取或(|) 操作 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)>x∣y≥max(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)。
逐渐积累吧!