hdu 5726 GCD(线段树上gcd,好题)

题目链接
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

Author
HIT

Source
2016 Multi-University Training Contest 1
思路:区间gcd我们可以用线段树求,可是相同的对数怎么求呢?我们知道一个长度为n的子区间内的gcd个数肯定是不超过log个的,因为枚举是可能的,当枚举到a【i】时,遍历一下之前在【1,a【i-1】】求的gcd的种类和个数进行计数,查询时就可以O(1)。比如说前面1到a【i-1】中已经有一个gcd是x,那么现在gcd(x,a【i】)等于y,那么cnt【y】就等于本身存在的个数+gcd(x)的个数,存gcd的话用map映射一下。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+1;
ll a[maxn];
ll gcd (ll a,ll b)
{
    return b==0?a:gcd(b,a%b);
}
struct node{
    int l,r;
    ll num;
}tree[maxn<<2];
map<ll,ll>p1,p2,cnt;
void build(int l,int r,int x)
{
    tree[x].l=l,tree[x].r=r;
    if(l==r){
        tree[x].num=a[l];return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,x<<1);
    build(mid+1,r,x<<1|1);
    tree[x].num=gcd(tree[x<<1].num,tree[x<<1|1].num);
}
ll query(int x,int l,int r)
{
    if(l==tree[x].l&&tree[x].r==r) return tree[x].num;
    int mid=(tree[x].l+tree[x].r)>>1;
    if(r<=mid) return query(x<<1,l,r);
    else if(l>mid) return query(x<<1|1,l,r);
    else return gcd(query(x<<1,l,mid),query(x<<1|1,mid+1,r));
}
int main()
{
    int T,n,m,l,r;
    scanf("%d",&T);
    for(int j=1;j<=T;++j)
    {
        printf("Case #%d:\n",j);
        scanf("%d",&n);
        p1.clear(),p2.clear(),cnt.clear();
        for(int i=1;i<=n;++i)  
        {
            scanf("%lld",&a[i]);
            cnt[a[i]]++;
            p2[a[i]]++;
            for(auto it=p1.begin();it!=p1.end();it++)
            {
                ll t=gcd(a[i],it->first);
                cnt[t]+=it->second;
                p2[t]+=it->second;
            }
            p1.clear();
            for(auto it=p2.begin();it!=p2.end();it++) p1[it->first]=it->second;
            p2.clear();
        }
        build(1,n,1);
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d%d",&l,&r);
            ll ans=query(1,l,r);
            printf("%lld %lld\n",ans,cnt[ans]);
        }
    }
}
发布了150 篇原创文章 · 获赞 0 · 访问量 5532

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/104591020