Maximum Value | CF484B
2100
2100
2100 分 给你长度为
n
n
n 的序列
A
[
1
,
n
]
A[1,n]
A[1,n] 令
1
≤
i
,
j
≤
n
1\le i,j\le n
1≤i,j≤n 且
A
[
i
]
≥
A
[
j
]
A[i]\ge A[j]
A[i]≥A[j] , 求
A
[
i
]
%
A
[
j
]
A[i]\% A[j]
A[i]%A[j] 的最大值
1
≤
n
≤
2
×
1
0
5
1\le n\le 2\times10^5
1≤n≤2×105
1
≤
A
[
i
]
≤
1
0
6
1\le A[i]\le 10^6
1≤A[i]≤106
思路
这题真的绝了… 首先暴力肯定没法做。我们考虑化简一下式子:
A
[
i
]
%
A
[
j
]
A[i]\%A[j]
A[i]%A[j] 就是
∃
k
∈
Z
\exist k\in Z
∃k∈Z,满足
A
[
i
]
=
x
+
k
×
A
[
j
]
A[i]=x+k \times A[j]
A[i]=x+k×A[j] 我们需要求的就是
max
{
x
}
\max\{x\}
max{x}
我们可以暴力枚举
k
k
k ,也就是暴力枚举
k
×
A
[
j
]
k\times A[j]
k×A[j] 然后怎么去获得最大的
x
x
x 呢? 其实就是找到在
[
(
k
−
1
)
A
[
j
]
,
k
×
A
[
j
]
]
[(k-1)A[j],k\times A[j]]
[(k−1)A[j],k×A[j]] 区间里面最右边的数字
y
y
y 然后把这个
y
y
y 去处理一下
y
%
A
[
j
]
y\% A[j]
y%A[j] ,更新这个最大值
怎么找这一段区间里的最靠右的值呢? 因为我们数字很小
<
1
0
6
<10^6
<106 ,我们就记一个
p
r
e
[
i
]
pre[i]
pre[i] 数组,表示距离
i
i
i 且在
i
i
i 左边的最大的位置
j
j
j 然后就可以了
代码
时间复杂度:
O
(
N
log
N
)
O(N\log N)
O(NlogN)
bool have[MAX];int pre[MAX];int YOU =1000000;intmain(){int n;n =read();for(int i =1;i <= n;++i){int t =read();
have[t]=1;
pre[t]++;}for(int i =1;i <= YOU;++i){if(pre[i])pre[i]= i;else pre[i]= pre[i-1];}int ans =0;for(int i =1;i <= YOU;++i){if(!have[i])continue;for(int j = i + i;j <= YOU;j+=i){
ans =max(ans,pre[j-1]% i);}
ans =max(ans,pre[YOU]% i);}
cout << ans;return0;}