HDU5726 线段树求解区间GCD

GCD

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 5302    Accepted Submission(s): 1908

Problem Description

Give you a sequence of N(N≤100,000) integers : a1,...,an(0

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

Author

HIT

Source

2016 Multi-University Training Contest 1

Recommend

wange2014   |   We have carefully selected several similar problems for you:  6396 6395 6394 6393 6392 

线段树求解区间GCD
题意:
给n个数,q次查询,首先问区间[l,r]的gcd(a[l],a[l+1],a[l+2]....a[r-1],a[r]),然后输出与区间[l,r]的gcd相等的区间的个数
第一问用线段树求解区间,第二问就是先预处理出以i为开头的区间的各自的GCD的值,用线段树来维护区间GCD和查询


#include
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
int n;
int num[maxn];
struct segtree{
    int g[maxn<<2];
    void build(int i,int l,int r)
    {
        if(l==r){
            g[i]=num[l];
            return ;
        }
        int mid=(l+r)>>1;
        build(i<<1,l,mid);
        build(i<<1|1,mid+1,r);
        g[i]=__gcd(g[i<<1],g[i<<1|1]);
    }
    int query(int i,int l,int r,int L,int R)
    {
        if(L<=l&&r<=R)  return g[i];
        int mid=(l+r)>>1;
        int ls=0,rs=0;
        if(L<=mid)
            ls=query(i<<1,l,mid,L,R);
        if(R>mid)
            rs=query(i<<1|1,mid+1,r,L,R);
        if(!ls) swap(ls,rs);
        return __gcd(ls,rs);
    }
    int search(int i,int l,int r,int L,int R,int cur,int &GCD)
    {
        if(L<=l&&r<=R)
        {
            if(__gcd(g[i],GCD)>1,ls=0,rs=0;
                ls=search(i<<1,l,mid,L,R,cur,GCD);
                if(ls)  return ls;
                rs=search(i<<1|1,mid+1,r,L,R,cur,GCD);
                return rs;
            }
        }
        else{
            GCD=__gcd(g[i],GCD);
            return 0;
        }
    }
    int mid=(l+r)>>1,ls=0,rs=0;
    if(L<=mid)  ls=search(i<<1,l,mid,L,R,cur,GCD);
    if(ls)  return ls;
    if(R>mid)
        rs=search(i<<1|1,mid+1,r,L,R,cur,GCD);
    return rs;
}
}seg;

mapM;
int main()
{
    int T,Case=1;
    scanf("%d",&T);
    while(T--){
        M.clear();
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
        }
        seg.build(1,1,n);
        int GCD,nex;
        for(int i=1;i<=n;i++)
        {
            int g=seg.query(1,1,n,i,n);
            for(int now=i,cur=num[i];now<=n;)
            {
                if(g==cur)
                {
                    M[g]+=n-now+1;
                    break;
                }
                GCD=num[i];
                nex=seg.search(1,1,n,i,n,cur,GCD);
                M[cur]+=nex-now;
                now=nex;
                cur=__gcd(num[now],cur);
            }
        }
        int q;
        scanf("%d",&q);
        printf("Case #%d:\n",Case++);
        int a,b,ans;
        for(int i=1;i<=q;i++)
        {
            scanf("%d%d",&a,&b);
            ans=seg.query(1,1,n,a,b);
            printf("%d %lld\n",ans,M[ans]);
        }
    }
    return 0;
}

 

你可能感兴趣的:(线段树,数论)