文章目录

题目链接:

51nod 1421
cf484B

参考博客: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;
	}
}

然后就是因为 a i a_i ai的数据范围是1e6,所以阔以用个数组b[i]来保存小于 i 的最大的a[]数组中的数是多少,这样中间那层二分就变成 O ( 1 ) O(1) 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;
	}
}