小鱼吃大鱼
题目链接:luogu U138097
题目大意
给你 n 个数,你可以选两个数,让小的取模大的,问你结果最大可以是多少。
思路
直接暴力搞当然会 T 飞,我们考虑枚举取模的数。
然后再枚举其倍数,然后这样是
n
l
o
g
n
nlogn
nlogn。
接着枚举倍数那我们这一段之前我们就要找最接近倍数的数,也就是这一段里面最大的。
然后我们可以用一个前缀和先搞着,然后就二分最大的位置,判断后面那一大段那里面有没有数。
总的复杂度是 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n),还是可以过的。
然后记得判一下边边角角的地方就可以了。
代码
#include<cstdio>
#include<iostream>
using namespace std;
int n, x, bg[2000001];
int answer, re;
int in[1000001];
char c;
int read() {
re = 0; c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') {
re = (re << 3) + (re << 1) + c - '0';
c = getchar();
}
return re;
}
int main() {
// freopen("sj.txt", "r", stdin);
n = read();
for (int i = 1; i <= n; i++) {
x = read();
in[x] = 1;
}
for (int i = 1; i <= 1000000; i++) {
bg[i] = bg[i - 1] + in[i];
}
for (int i = 2; i <= 1000000; i++)
if (in[i]) {
int l = answer, r = i - 1, ans = 0, rr = i - 1;
if (i + r > 1000000) r = rr = 1000000 - i;
while (l <= r) {
int mid = (l + r) >> 1;
bool yes = 0;
for (int j = i; j <= 1000000; j += i) {
if (j + mid - 1 <= 1000000 && bg[min(j + rr, 1000000)] - bg[j + mid - 1]) {
yes = 1; break;
}
}
if (yes) ans = mid, l = mid + 1;
else r = mid - 1;
}
answer = max(answer, ans);
}
printf("%d", answer);
return 0;
}