• 某次模拟赛 数字对


    题目描述 Description

    小 H 是个善于思考的学生,现在她又在思考一个有关序列的问题。
    她的面前浮现出一个长度为 n 的序列{ai},她想找出一段区间[L, R](1 <= L <= R <= n)。这个特殊区间满足,存在一个 k(L <= k <= R),并且对于任意的 i(L <= i <= R),ai 都能被 ak 整除。这样的一个特殊区间 [L, R]价值为 R - L。
    小 H 想知道序列中所有特殊区间的最大价值是多少,而有多少个这样的区间呢?这些区间又分别是哪些呢?你能帮助她吧。

    输入描述 Input Description

    第一行,一个整数 n.
    第二行,n 个整数,代表 ai.

    输出描述 Output Description

    第一行两个整数,num 和 val,表示价值最大的特殊区间的个数以及最大价值。
    第二行 num 个整数,按升序输出每个价值最大的特殊区间的 L.

    样例输入 Sample Input

    5
    4 6 9 3 6

    样例输出 Sample Output

    1 3
    2

    数据范围及提示 Data Size & Hint

    30%: 1 <= n <= 30 , 1 <= ai <= 32.
    60%: 1 <= n <= 3000 , 1 <= ai <= 1024.
    80%: 1 <= n <= 300000 , 1 <= ai <= 1048576.
    100%: 1 <= n <= 500000 , 1 <= ai < 2 ^ 31.

    之前的一些废话:暑假作业发现还有论语视频没有看,十分慌张

    题解:传说中的暴力踩标程。

    解法1:先说正解吧,首先最大价值是可以进行二分的,如何判断解是否可行呢?当前解是mid,枚举每一个长度为mid+1的区间,判这个区间是否合法,如果合法就把该区间左端放入队列中,最后检查队列中是否有元素即可(即有没有符合的区间)至于如何判区间是否合法,根据题意只要区间最小值与区间GCD相等就可以,这个可以通过RMQ来处理,O(n log n)预处理,O(1)查询,至于区间GCD通过类似的方法处理即可。    总复杂度O(n log n*log n)  

    解法2:再说暴力。对于序列中每一个元素进行考虑,假定当前数为ak,那么我们需要计算出ak所属于的最长区间。向左向右分别扫,如果碰到一个数不能整除ak就停,最后计算出该区间长度[L,R]。然后还有一个优化,处理完第i个数后,我们没有必要继续处理第i+1个数,而是直接从第I个数所对应的R的下一个数开始处理即可,因为我们可以证明,从第i+1个数到第R个数中选它们做ak的答案显然没有拿第i个数当ak更优。复杂度O(

    解法3:还有一种类似暴力的做法,该做法与暴力做法的区别就是ak不用往左往右扫了,而是通过二分来确定区间长度,不过也需要区间GCD预处理。复杂度O(n log n*log n)

    最后实测结果是解法2速度最快 ,解法1第二 解法3第三

    代码:

    解法1&&解法2的:

    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> PII;
    #define mem(a,b) memset(a,b,sizeof(a))
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    const int maxn=500010,MAXlog=20;
    int n,a[maxn],f[maxn],ans,cnt,Min[MAXlog][maxn],GCD[MAXlog][maxn],len[maxn],L,R,A[maxn],l;
    bool ok;
    int gcd(int a,int b){return b==0 ? a : gcd(b,a%b);}
    int MINquery(int L,int R)
    {
        int bin=len[R-L+1];
        return min(Min[bin][L],Min[bin][R-(1<<bin)+1]);
    }
    int GCDquery(int L,int R)
    {
        int bin=len[R-L+1];
        return gcd(GCD[bin][L],GCD[bin][R-(1<<bin)+1]);
    }
    bool check(int index)
    {
        l=0;
        for(int i=1;i+index-1<=n;i++)if(GCDquery(i,i+index-1)==MINquery(i,i+index-1))A[l++]=i;
        if(l)ans=max(ans,index);
        return l;
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)Min[0][i]=GCD[0][i]=a[i]=read();
        for(int i=1;(1<<i)<=n;i++)
            for(int j=1;j+(1<<(i-1))<=n;j++)
            {
                Min[i][j]=min(Min[i-1][j],Min[i-1][j+(1<<(i-1))]);
                GCD[i][j]=gcd(GCD[i-1][j],GCD[i-1][j+(1<<(i-1))]);
            }
        for(int i=2;i<=n;i++)len[i]=len[i>>1]+1;
        L=1;R=n;
        while(R-L>1)
        {
            int mid=(L+R)>>1;
            if(check(mid))L=mid;
            else R=mid;
        }
        check(L);check(R);check(ans);
        printf("%d %d
    ",l,ans-1);
        for(int i=0;i<l;i++)
        {
            if(!ok)printf("%d",A[i]),ok=1;
            else printf(" %d",A[i]);
        }
        printf("
    ");
        return 0;
    }
    View Code
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> PII;
    #define mem(a,b) memset(a,b,sizeof(a))
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    const int maxn=500010;
    int n,a[maxn],f[maxn],ans,cnt;
    bool ok;
    int gcd(int a,int b){return b==0 ? a : gcd(b,a%b);}
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)a[i]=read();
        for(int i=1;i<=n;i++)
        {
            int L=i,R=i;
            for(L=i;L>0;L--)if(a[L]%a[i]!=0)break;
            for(R=i;R<=n;R++)if(a[R]%a[i]!=0)break;
            L++;R--;
            f[L]=R-L;
            i=R;
        }
        for(int i=1;i<=n;i++)ans=max(ans,f[i]);
        for(int i=1;i<=n;i++)if(f[i]==ans)cnt++;
        printf("%d %d
    ",cnt,ans);
        for(int i=1;i<=n;i++)
            if(f[i]==ans)
            {
                if(!ok)printf("%d",i),ok=1;
                else printf(" %d",i);
            }
        printf("
    ");
        return 0;
    }
    View Code

    解法3懒得写了。

    总结:考试时候想到了解法2,但是没有勇气去写,像这种代码复杂度又低却跑得贼快的写起来真是太值了。

  • 相关阅读:
    jenkins构建完成后,执行的命令行的东西也会自动结束的解决办法
    解决ansible上传速度慢的问题
    uniq的坑坑
    tomcat问题
    R语言入门:对于boxplot()箱型图的直观理解
    R语言入门:条形图barplot()的绘制
    R语言入门:数据框的创建和访问
    Python当中的命令行参数sys.argv[]的使用方法
    R语言清除单个变量和全部变量
    linux下添加环境变量
  • 原文地址:https://www.cnblogs.com/FYH-SSGSS/p/7351751.html
Copyright © 2020-2023  润新知