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
![](http://espresso.codeforces.com/fab6bb390f875e9dbc8692275347ad1e68de8347.png)
(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
output
找出满足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;
}
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
![](http://espresso.codeforces.com/fab6bb390f875e9dbc8692275347ad1e68de8347.png)
(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;
}
相关文章推荐
- 【CF689D Friends and Subsequences】二分搜索,区间查询
- CF 551c 二分搜索+思维题
- CF-E. Holes(区间分块,二分思想)
- CF-E. Holes(区间分块,二分思想)
- POJ - 2456/USACO - Feb05 Gold Aggressive cows 二分搜索+区间选点+贪心
- CF 782 B. The Meeting Place Cannot Be Changed (二分搜索)
- HDU 5289 Assignment [RMQ区间查询+二分搜索]
- CF_Round274_Div1_B_Long Jump_二分搜索
- cf 768 B(二分搜索+线段树思维)@
- cf 484B 二分+贪心
- (算法)二分查找的搜索区间
- 二分搜索的区间问题
- 第2章 递归与分治策略,二分搜索技术(查找不成功时,返回区间位置)
- 最大化平均值(二分搜索)
- js实现二分搜索的两种方法
- cf 371c 二分
- 【BZOJ1014】【JSOI2008】火星人prefix Splay处理区间,hash+dichotomy(二分)check出解
- ZOJ 1112 Dynamic Rankings【动态区间第K大,整体二分】
- CF 6E Exposition(RMQ | 线段树,二分)
- cf Castle Defense(二分+滑动窗口)