您的位置:首页 > 其它

cf 484b 二分搜索/区间最值

2015-02-23 17:02 393 查看
B. Maximum Value

time limit per test
1 second

memory limit per test
256 megabytes

input
standard input

output
standard output

You are given a sequence a consisting of n integers.
Find the maximum possible value of 

 (integer
remainder of ai divided
by aj),
where 1 ≤ i, j ≤ n and ai ≥ aj.

Input

The first line contains integer n — the length of the sequence (1 ≤ n ≤ 2·105).

The second line contains n space-separated integers ai (1 ≤ ai ≤ 106).

Output

Print the answer to the problem.

Sample test(s)

input
3
3 4 5


output
2


找出满足a[i]>=a[j]的a[i]%a[j]的最大值。

这题数据有个特点,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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: