这题数据有个特点,ai <= 10^6。所以我想到了对于aj,找出mod它得到最大的值,就可以循环找出[k*aj+1,k*aj+aj-1]区间中出现过的最大值。由于查询的次数非常多,所以用st算法查询区间最大值会好很多。另外有几个地方可以做一些优化。对数据可以进行离散化,去除重复的,减少重复查询的时间。查询最大值时需要log(b-a+1)/log(2),由于查询很多次所以预处理出1-10^6所有的log值会快很多。st查询函数前加inline也会快很多 (没加inline前904ms,加了685ms)
看了别人的解题报告,发现有比较简洁的做法。。。枚举aj的倍数,二分搜索找出小于aj的倍数的最大值即可。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 200005
int n;
int a[maxn];
int h[5*maxn];
int maxi;
double log1[5*maxn];
int stmax[5*maxn][21];
void get_st()
{
for(int i = 1; i <= maxi; i++)
stmax[i][0] = h[i];
for(int j = 1; (1<<j) <= maxi; j++)
for(int i = 1; i+(1<<j)-1 <= maxi; i++)
stmax[i][j] = max(stmax[i][j-1], stmax[i+(1<<(j-1))][j-1]);
}
inline int get_max(int a, int b)
{
int j = log1[b-a+1]/log1[2];
return max(stmax[a][j], stmax[b-(1<<j)+1][j]);
}
int main()
{
for(int i = 1; i < 5*maxn; i++)
log1[i] = log(i);
while(scanf("%d", &n)!=EOF){
for(int i = 0; i < n; i++)
scanf("%d", a+i);
sort(a, a+n);
n = unique(a, a+n)-a;
maxi = a[n-1];
memset(h, 0, sizeof(h));
for(int i = 0; i < n; i++)
h[a[i]] = a[i];
get_st();
int ans = 0;
for(int i = 0; i < n; i++){
for(int l = a[i]+1, r = 2*a[i]-1; l <= r && l <= maxi && ans < a[i]-1; l+=a[i], r+=a[i])
ans = max(ans, get_max(l,min(r,maxi))-l+1);
}
printf("%d\n", ans);
}
return 0;
}