题面
题意
给出n个数,求其中选择两个数,较大的数模较小的数的最大值。
做法
一开始想到的算法很奇怪,对于a求它模那个数的值最大,将小于a的数小于等于它的最大倍数放到set中,然后在增大a的同时,不断更新set中的数字的值,然后不断取最大值即可。
时间复杂度好像最劣是O(n*log(n)^2).
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#define P pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define N 200100
using namespace std;
int n,num[N],t,ans;
P tmp;
set<P>se;
int main()
{
int i,j;
cin>>n;
for(i=1; i<=n; i++)
{
scanf("%d",&num[i]);
}
sort(num+1,num+n+1);
se.insert(mp(num[2]/num[1]*num[1],num[1]));
for(i=2; i<=n; i++)
{
for(;;)
{
tmp=(*se.begin());
if(num[i]/tmp.se != tmp.fi/tmp.se)
{
se.erase(tmp);
se.insert(mp(num[i]/tmp.se*tmp.se,tmp.se));
}
else
{
ans=max(ans,num[i]%tmp.se);
break;
}
}
se.insert(mp(num[i+1]/num[i]*num[i],num[i]));
}
cout<<ans;
}
虽然A了,但时间复杂度终究不对。
标算
首先预处理出,在原来数列中小于i的最大数。
然后算小于a[i]的k倍的最大数,即可更新答案。
也就是对于数字i,计算i~2* i,2* i~3* i,3* i~4* i……中的被除数。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 200100
#define M 2001000//注意要多开一倍,因为num[i]*j可能大于1000000
using namespace std;
int n,m,num[N],pos[M],t,ans;
bool P[M];
int main()
{
int i,j,p,q;
cin>>n;
for(i=1; i<=n; i++)
{
scanf("%d",&p);
if(P[p]) continue;
P[p]=1;
num[++m]=p;
}
n=m;
sort(num+1,num+n+1);
for(i=M-1000,j=n;i>=1;i--)
{
if(num[j]==i&&j>1) j--;
pos[i]=num[j];
}
for(i=1;i<=n;i++)
{
for(j=2;num[i]*j<=M-1000;j++)
{
ans=max(ans,pos[num[i]*j]%num[i]);
}
}
cout<<ans;
}