zoukankan      html  css  js  c++  java
  • HDU 5726 GCD 【GCD】【ST表+二分】【线段树+暴力枚举】

    题意

    给一串数列,求区间GCD和整个数列中与该区间GCD相等的区间数

    分析

    首先区间GCD易求,用能求RMQ的方法都可以,比如ST表、线段树。关键是如何求第二个问题,这里有两种做法:
    方法一
    利用GCD的性质,若固定区间左端点,增大右端点,区间GCD必然非递增。因此我们可以遍历区间左端点,用二分求出以该端点起始的区间的所有gcd的情况及其对应的区间个数,并用map记录。该过程复杂度可近似看做O(nlogn)。写线段树有可能会T,最好写ST表。
    方法二
    用map暴力枚举。从左向右遍历,用两个map,一个存答案也就是某种gcd的个数,另一个存以当前位置结尾的所有区间的gcd情况。每向右移动一次,就将这个新元素与前一个位置结尾的情况全部gcd一遍,更新存答案的map,同时也更新另一个map

    AC代码(方法一)

    //HDU 5726 GCD 
    //AC 2017-1-17 19:21:30
    //Sparse table, GCD, Binary Search
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+100;
    
    int N;
    long long a[maxn];
    
    long long ST[maxn][30];
    
    void ST_init()
    {
        for(int i=1;i<=N;++i)
            ST[i][0]=a[i];
        for(int j=1;j<30;++j)
        {
            for(int i=1;i<=N;++i)
            {
                if(i+(1<<j)-1>N) break;
                ST[i][j]=__gcd(ST[i][j-1],ST[i+(1<<(j-1))][j-1]);
            }
        }
        return;
    }
    
    long long ST_query(int s,int e)
    {
        int k=(int)((log(e-s+1.0)/log(2.0)));
        return __gcd(ST[s][k],ST[e-(1<<k)+1][k]);
    }
    
    map<long long,long long> ans;
    
    void setTable()
    {
      ans.clear();
      for(int i=1;i<=N;i++)
      {
        int g=ST[i][0],j=i;
        while(j<=N)
        {
          int l=j,r=N;
          while(l<r)
          {
            int mid=(l+r+1)>>1;
            if(ST_query(i,mid)==g) l=mid;
            else r=mid-1;
          }
          ans[g]+=l-j+1;
          j=l+1;
          g=ST_query(i,j);
        }
      }
    }
    
    int main()
    {
        int T;scanf("%d",&T);
        for(int kase=1;kase<=T;++kase)
        {
            scanf("%d",&N);
            for(int i=0;i<N;++i)
                scanf("%lld",a+i+1);
            ST_init();
            setTable();
            int Q;
            scanf("%d",&Q);
            int l,r;
            printf("Case #%d:
    ",kase);
            while(Q--)
            {
                scanf("%d %d",&l,&r);
                long long gcd=ST_query(l,r);
                printf("%lld %lld
    ",gcd,ans[gcd]);
            }
        }
        return 0;
    }
    

    AC代码(方法二)

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+100;
    
    int N;
    long long a[maxn];
    struct segTree
    {
        long long gcd[maxn*4];
        void Push_Up(int x)
        {
            gcd[x]=__gcd(gcd[x<<1],gcd[x<<1|1]);
            return;
        }
        void build(int x,int l,int r)
        {
            if(l==r)
            {
                gcd[x]=a[l];
                return;
            }
            int mid=(l+r)>>1;
            build(x<<1,l,mid);
            build(x<<1|1,mid+1,r);
            Push_Up(x);
            return;
        }
        long long query(int x,int beg,int endd,int l,int r)
        {
            if(l==beg&&r==endd)
                return gcd[x];
            int mid=(l+r)>>1;
            if(beg>mid)
                return query(x<<1|1,beg,endd,mid+1,r);
            else if(endd<=mid)
                return query(x<<1,beg,endd,l,mid);
            else
                return __gcd(query(x<<1,beg,mid,l,mid),query(x<<1|1,mid+1,endd,mid+1,r));
        }
    }Tree;
    
    map<long long,long long> ans;
    map<long long,long long> mp1;
    map<long long,long long> mp2;
    
    int main()
    {
        int T;scanf("%d",&T);
        for(int kase=1;kase<=T;++kase)
        {
            scanf("%d",&N);
            for(int i=0;i<N;++i)
                scanf("%lld",a+i+1);
            Tree.build(1,1,N);
            ans.clear();mp1.clear();mp2.clear();
            mp1[a[1]]++;ans[a[1]]++;
            for(int i=2;i<=N;++i)
            {
                mp2[a[i]]++;
                ans[a[i]]++;
                for(map<long long,long long>::iterator ita=mp1.begin();ita!=mp1.end();++ita)
                {
                    long long now=__gcd(a[i],ita->first);
                    ans[now]+=ita->second;
                    mp2[now]+=ita->second;
                }
                swap(mp1,mp2);
                mp2.clear();
            }
            int Q;
            scanf("%d",&Q);
            int l,r;
            printf("Case #%d:
    ",kase);
            while(Q--)
            {
                scanf("%d %d",&l,&r);
                long long gcd=Tree.query(1,l,r,1,N);
                printf("%lld %lld
    ",gcd,ans[gcd]);
            }
        }
        return 0;
    }
  • 相关阅读:
    【vue】vue +element 搭建项目,vue-cli 如何打包上线
    【移动端】单位em相关资料
    管道 |、|&、tee
    重定向
    Bash快捷键
    man 与 help
    linux磁盘分区、格式化、挂载
    目录(cd mkdir rmdir rm pwd ls) 文件(ln touch mv rm cat more head rail) 文件权限(chmod chown chgrp) 文件通配符(* ? [])
    用户环境变量 shell变量 别名
    用户、组和身份认证
  • 原文地址:https://www.cnblogs.com/DrCarlluo/p/6580576.html
Copyright © 2011-2022 走看看