文章目录
题目链接:
参考博客:https://blog.csdn.net/linkfqy/article/details/78300976
对哈,里面那层循环的复杂度是调和级数,数越大枚举这个数的倍数就越小
然后就是找一段范围内最大的数,最开始竟然没有反应过来,就是找这段范围的最右边看在哪里,他的左边一个不就是这段范围里最大的嘛~
#include"bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn=2e5+5;
int a[maxn];
int main()
{
int N;
while(cin>>N)
{
int ans=0;
for(int i=1;i<=N;i++)scanf("%d",a+i);
sort(a+1,a+1+N);
for(int i=1;i<=N;i++)
{
if(a[i]==a[i-1])continue;//只要第一个来判断
for(int k=2;k*a[i]<=a[N];k++)
{
int pos=lower_bound(a+1,a+1+N,k*a[i])-a;
ans=max(ans,a[pos-1]%a[i]);//找到a[pos]这个数,再往前面一个数a[pos-1]肯定在[k*ai,(k+1)*ai]范围内
}
ans=max(ans,a[N]%a[i]);//剩下不够倍数的一段,最后的是最大的
}
cout<<ans<<endl;
}
}
然后就是因为 ai的数据范围是1e6,所以阔以用个数组b[i]来保存小于 i 的最大的a[]数组中的数是多少,这样中间那层二分就变成 O(1)的了。用这种方法只跑了109ms,而上面二分那个跑路608ms,优化很明显呀~
#include"bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn=2e5+5;
int a[maxn],b[maxn*5];//b[i]表示a[]数组中比i小的最大的数
int main()
{
int N;
while(cin>>N)
{
int ans=0;
for(int i=1;i<=N;i++)scanf("%d",a+i);
sort(a+1,a+1+N);
N=unique(a+1,a+1+N)-(a+1);
for(int i=1,j=0;i<=1000000;)
{
if(i>a[j]&&i<=a[j+1])b[i++]=a[j];
else if(j==N)b[i++]=a[N];
else j++;
}
for(int i=1;i<=N;i++)
{
for(int k=2;k*a[i]<=a[N];k++)
{
ans=max(ans,b[k*a[i]]%a[i]);
}
ans=max(ans,a[N]%a[i]);//剩下不够倍数的一段,最后的是最大的
}
cout<<ans<<endl;
}
}