51Nod - 1421 最大MOD值

题面

题意

给出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;
}

猜你喜欢

转载自blog.csdn.net/yzyyylx/article/details/81013038