zoukankan      html  css  js  c++  java
  • HDU5726 GCD(二分 + ST表)

    题目

    Source

    http://acm.hdu.edu.cn/showproblem.php?pid=5726

    Description

    Give you a sequence of N(N≤100,000) integers : a1,...,an(0<ai≤1000,000,000). There are Q(Q≤100,000) queries. For each query l,r you have to calculate gcd(al,,al+1,...,ar) and count the number of pairs(l′,r′)(1≤l<r≤N)such that gcd(al′,al′+1,...,ar′) equal gcd(al,al+1,...,ar).

    Input

    The first line of input contains a number T, which stands for the number of test cases you need to solve.

    The first line of each case contains a number N, denoting the number of integers.

    The second line contains N integers, a1,...,an(0<ai≤1000,000,000).

    The third line contains a number Q, denoting the number of queries.

    For the next Q lines, i-th line contains two number , stand for the li,ri, stand for the i-th queries.

    Output

    For each case, you need to output “Case #:t” at the beginning.(with quotes, t means the number of the test case, begin from 1).

    For each query, you need to output the two numbers in a line. The first number stands for gcd(al,al+1,...,ar) and the second number stands for the number of pairs(l′,r′) such that gcd(al′,al′+1,...,ar′) equal gcd(al,al+1,...,ar).

    Sample Input

    1
    5
    1 2 4 6 7
    4
    1 5
    2 4
    3 4
    4 4

    Sample Output

    Case #1:
    1 8
    2 4
    2 4
    6 1

    分析

    题目大概说给一个包含n个数的序列,多次询问有多少个区间GCD值等于某个区间的gcd值。

    任何一个区间不同的GCD个数是log级别的,因为随着右端点向右延伸GCD是单调不增的,而每次递减GCD至少除以2。

    考虑固定左端点,最多就nlogn种GCD,可以直接把所有区间GCD值预处理出来,用map存储各种GCD值的个数,查询时直接输出。

    具体是这样处理的:枚举左端点,进行若干次二分查找,看当前GCD值最多能延伸到哪儿,进而统计当前GCD值的数量。

    而求区间GCD,用ST表,预处理一下,就能在O(1)时间复杂度求出任意区间的gcd了。

    代码

    #include<cstdio>
    #include<cmath>
    #include<map>
    #include<algorithm>
    using namespace std;
    
    int gcd(int a,int b){
        while(b){
            int t=b;
            b=a%b;
            a=t;
        }
        return a;
    }
    
    int n,st[17][111111];
    void init(){
        for(int i=1; i<17; ++i){
            for(int j=1; j<=n; ++j){
                if(j+(1<<i)-1>n) continue;
                st[i][j]=gcd(st[i-1][j],st[i-1][j+(1<<i-1)]);
            }
        }
    }
    int logs[111111];
    int query(int a,int b){
        int k=logs[b-a+1];
        return gcd(st[k][a],st[k][b-(1<<k)+1]);
    }
    
    int main(){
        for(int i=1; i<=100000; ++i){
            logs[i]=log2(i)+1e-6;
        }
        int t;
        scanf("%d",&t);
        for(int cse=1; cse<=t; ++cse){
            scanf("%d",&n);
            for(int i=1; i<=n; ++i){
                scanf("%d",&st[0][i]);
            }
    
            init();
    
            map<int,long long> rec;
            for(int i=1; i<=n; ++i){
                int g=st[0][i],j=i;
                while(j<=n){
                    int l=j,r=n;
                    while(l<r){
                        int mid=l+r+1>>1;
                        if(query(i,mid)==g) l=mid;
                        else r=mid-1;
                    }
                    rec[g]+=(l-j+1);
                    j=l+1;
                    g=query(i,j);
    
                }
            }
    
            printf("Case #%d:
    ",cse);
            int q,a,b;
            scanf("%d",&q);
            while(q--){
                scanf("%d%d",&a,&b);
                int g=query(a,b);
                printf("%d %lld
    ",g,rec[g]);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    c++虚函数表 Brew VTBL
    c++ 类数据成员的定义、声明
    变量声明和定义的区别
    C++ 对象间的赋值与拷贝构造函数
    Android应用程序构成
    android平台的技术架构
    认识Service
    Application的作用
    Context的作用
    如何切换到自定义的Activity
  • 原文地址:https://www.cnblogs.com/WABoss/p/5686994.html
Copyright © 2011-2022 走看看