zoukankan      html  css  js  c++  java
  • 51nod 1421 最大MOD值(高妙的调和级数复杂度)

    有一个a数组,里面有n个整数。现在要从中找到两个数字(可以是同一个) ai,aj ,使得 ai mod aj 最大并且 ai  aj

    Input
    单组测试数据。
    第一行包含一个整数n,表示数组a的大小。(1 ≤ n ≤ 2*10^5)
    第二行有n个用空格分开的整数ai (1 ≤ ai ≤ 10^6)。
    Output
    输出一个整数代表最大的mod值。
    Input示例
    3
    3 4 5
    Output示例
    2

    题解:首先考虑mod的真正定义
    a%b=a/b*b+c
    思考一下其实是kb+c的形式,画在数轴上就是

    很显然,如果有一个数x%a>b%a他肯定会在(k*a+b,(k+1)*a)的区间之中,到底有没有这些数存在可以用前缀和O(1)查询

    所以因此我们就可以对c即余数进行二分了,不过二分的时候检验是O(nlogn)的,因为会枚举每一个数的倍数的区间,总复杂度大约是调和级数即logn 但其实仔细一想这是不满的

    在套上二分,复杂度是O(nlognlogn) 

    代码如下:

    #pragma GCC optimize("inline",3)
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    int vis[4000010],sum[4000010],k,n,a[200010],cnt;
    
    int check(int x)
    {
        for(register int i=1;i<=cnt;++i)
        {
            for(register int j=a[i];j<=1e6;j+=a[i])
            {
                if(sum[j+a[i]-1]-sum[j+x-1]>0)
                {
                    return 1;
                }
            }
        }
        return 0;
    }
    
    int main()
    {
        scanf("%d",&n);
        int tmp;
        for(register int i=1;i<=n;++i)
        {
            scanf("%d",&tmp);
            if(!vis[tmp])
            {
                vis[tmp]=1;
            }
        }
        for(register int i=1;i<=2e6;++i)
        {
            sum[i]=sum[i-1]+vis[i];
        }
        for(int i=1;i<=1e6;i++)
        {
            if(vis[i])
            {
                a[++cnt]=i;
            }
        }
        register int l=0,r=2e6,mid;
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(check(mid))
            {
                l=mid;
            }
            else
            {
                r=mid-1;
            }
            if(r-l<=1)
            {
                r=check(r)?r:l;
                break;
            }
        }
        printf("%d
    ",r);
    }

    这个程序1e5跑跑是非常轻松的但是到了2e5就有点力不从心了

    直接提交到51nod上就大概只能过18个点

    于是考虑优化,其实只要知道了上面那个mod的定义,我们每次对于(k+1)*ai找到小于它的最大aj,那么这个aj%ai的值肯定是(k*ai,(k+1)*ai)区间内所有数%ai最大的

    因此我们可以先预处理出f[i]为比i小的最大ai,然后在向上面一样枚举区间对于每个区间计算最大模数更新答案,因为省去了二分,复杂度就是O(nlogn)

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    int b[2000010],a[200010],n,t,ans=-1;
    
    int cmp(int a,int b)
    {
        return a>b;
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        sort(a+1,a+n+1,cmp);
        int t=unique(a+1,a+n+1)-a-1;
        n=t;
        int j=1;
    
        for(int i=2e6;i>=1;i--)
        {
            while(j<=n&&a[j]>=i) j++;
            b[i]=a[j];
        }    
        for(int i=1;i<=n;i++)
        {
            for(int j=2;j<=2e6/a[i];j++)
            {
                ans=max(ans,b[a[i]*j]%a[i]);
            }
        }
        printf("%d
    ",ans);
    }
     

    yzy大佬用set随手A掉了此题
    详见这里
    https://blog.csdn.net/yzyyylx/article/details/81013038

  • 相关阅读:
    鼠标滑过,图片放大效果。
    ASP.NET自定义省市级联控件
    C++ Test单元测试工具
    网络超时检测
    电子工程师知识汇整【转】
    DDD进行调试 介绍 转
    VS2008配置PC Lint (静态代码检查工具PCLint)
    【转】三大UML建模工具Visio、Rational Rose、PowerDesign的区别
    第一个corba服务Hello World (转)
    python简介
  • 原文地址:https://www.cnblogs.com/stxy-ferryman/p/9299081.html
Copyright © 2011-2022 走看看