Problem J: 求个最大值
Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 60 Solved: 14
[ Submit][ Status][ Web Board]
Description
给出n(1 <= n <= 200000)个数字ai(1 <= ai <= 1000000),i为数字的下标,按输入顺序从1开始编号一直到n,求满足ai >= aj的最大的ai % aj。
Input
第一行一个数字n,第二行n个整数。
Output
题目要求的最大值。
Sample Input
22 3
Sample Output
1
这题比赛里已经想到思路了,就是不知道怎么去表示。。 思路很简单,设a, b , a > b -> a/b = k....r(r是余数),这样我们肯定希望a离着k*b越元越好。也就是我们枚举倍数的时候(比赛中写过枚举倍数,但是n*n的。。)我们希望b*k离着a越远越好,但是不能远过b的大小,这样就难处理了,但是可以转化成 (k+x)*b离着a越近越好,那枚举到每个数的倍数时候,对他有用的就只有一个离着这个数最近的a【i】了、、前缀处理下就好了。。记录1-maxn*2每个数比他小但是最大的a[i]就行。。
补充:
这题还可以二分做。。群里看到的
枚举每个j 对于j枚举他的倍数 然后在数组里二分
根据调和级数第二步是log的
因为你模的最大值应该是最接近他倍数的吧。。
比如:
假如ai的倍数2*ai存在的话
那么最靠近2*ai并且小于2*ai的数mod ai最大
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 1e6 + 10;
int b[maxn], a[maxn];
int main()
{
int n;
while(~scanf("%d", &n))
{
memset(b, 0, sizeof(b));
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
sort(a+1, a+1+n);
int index = a[1]+1;
a[n+1] = maxn*2;
for(int i = 2; i <= n+1; i++)
{
while(index <= a[i])
{
b[index++] = a[i-1];
}
}
int ans = 0;
for(int i = 1; i <= n; i++)
{
for(int j = a[i]*2; j <= maxn*2; j += a[i])
ans = max(ans, b[j]%a[i]);
}
printf("%d\n", ans);
}
return 0;
}
二分代码:
#include<bits/stdc++.h>
using namespace std;
int a[200010];
int main() {
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
sort(a, a+n);
n = unique(a, a+n) - a;
int ans = 0;
for(int i=0; i<n; i++) {
int cur = a[i];
cur += a[i];
while(1) {
int j = lower_bound(a, a+n, cur) - a;
j--;
if(j>=0 && a[j] > a[i]) {
ans = max(ans, a[j]%a[i]);
}
if(cur > a[n-1])
break;
cur += a[i];
}
}
cout << ans << endl;
}