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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM