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:\n",cse);
        int q,a,b;
        scanf("%d",&q);
        while(q--){
            scanf("%d%d",&a,&b);
            int g=query(a,b);
            printf("%d %lld\n",g,rec[g]);
        }
    }
    return 0;
}

 

posted @ 2016-07-20 08:52  WABoss  阅读(2102)  评论(0编辑  收藏  举报