hdu 5726 GCD 线段树dp求区间gcd 或者ST表二分求区间gcd 或者线段树二分求区间gcd

 

GCD

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


 

Problem 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

 

Author

HIT

 

Source

2016 Multi-University Training Contest 1

区间gcd有一个很强的性质,

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

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

所以这里既可以用ST表处理出ST[ i ][ j ] 表示从i开始长度为2的j次方的区间的gcd ,然后再固定左端点,进行若干次二分右端点,就可以求出所有的gcd,当然也可以用线段树来维护。

还有就是可以dp一下,dp[i][j] 表示的是以第i个结尾的最大公约数为j 的个数。

ST 代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N =1e5+5;
int ST[N][21];
int yi[25];
int a[N];
int n;

map<int ,ll >mp;

void init_yi()
{
    yi[0]=1;
    for(int i=1;i<=21;i++) yi[i]=yi[i-1]*2;
}

void init_ST()
{
    for(int i=1;i<=n;i++) ST[i][0]=a[i];
    for(int k=1;k<=19;k++)
    {
        for(int i=1;i<=n;i++)
        {
            if(i+yi[k]-1<=n){
                ST[i][k]=__gcd(ST[i][k-1],ST[i+yi[k-1]][k-1]);
            }
        }
    }
}

int jud(int l,int r)
{
    int k=(int)log2((double)(r-l+1));
    return __gcd(ST[l][k],ST[r-yi[k]+1][k]);
}

void init_mp()
{
    mp.clear();
    for(int i=1;i<=n;i++)
    {
        int now=a[i];
        int lb=i;
        int pos=i;
        while(pos<=n)
        {
            int l,r,mid;
            l=pos; r=n;
            int ans;
            while(l<=r)
            {
                mid=(l+r)>>1;
                if(jud(lb,mid)==now){
                    ans=mid;
                    l=mid+1;
                }
                else r=mid-1;
            }
            mp[now]+=1ll*(ans-pos+1);
            pos=ans+1;
            now=jud(lb,pos);
        }
    }
}

int main()
{
    init_yi();
    int T,kk;
    kk=0;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        init_ST();
        init_mp();
        int k;
        printf("Case #%d:\n",++kk);
        scanf("%d",&k);
        int l,r;
        while(k--)
        {
            scanf("%d %d",&l,&r);
            int ans=jud(l,r);
            printf("%d %lld\n",ans,mp[ans]);
        }
    }
    return 0;
}

dp代码:

#include<bits/stdc++.h>
#define lson (i<<1)
#define rson (i<<1|1)

using namespace std;
typedef long long ll;
const int N =1e5+5;
map<int ,ll > ans;
map<int ,ll > dp[N];  /// dp[i][j] 表示的是以第i个结尾的最大公约数为j 的个数。
map<int ,ll >::iterator it;
int a[N];

struct node
{
    int l,r;
    int val;
}tr[N<<2];
int n;

void push_up(int i)
{
    tr[i].val=__gcd(tr[lson].val,tr[rson].val);
}

void build(int i,int l,int r)
{
    tr[i].l=l; tr[i].r=r; tr[i].val=0;
    if(l==r){
        tr[i].val=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    push_up(i);
}

int query(int i,int l,int r)
{
    if(tr[i].l==l&&tr[i].r==r) return tr[i].val;
    int mid=(tr[i].l+tr[i].r)>>1;
    if(r<=mid) return query(lson,l,r);
    else if(l>mid) return query(rson,l,r);
    else{
        return __gcd(query(lson,l,mid),query(rson,mid+1,r));
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    int kk=0;
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        build(1,1,n);
        for(int i=0;i<=n;i++) dp[i].clear();
        ans.clear();
        dp[1][a[1]]+=1;
        ans[a[1]]+=1;
        for(int i=2;i<=n;i++){
            dp[i][a[i]]+=1; ans[a[i]]+=1;
            for(it=dp[i-1].begin();it!=dp[i-1].end();it++){
                int gcd=__gcd(it->first,a[i]);
                dp[i][gcd]+=it->second;
                ans[gcd]+=it->second;
            }
        }
        int k,l,r;
        scanf("%d",&k);
        printf("Case #%d:\n",++kk);
        while(k--)
        {
            scanf("%d %d",&l,&r);
            int gcd=query(1,l,r);
            printf("%d %lld\n",gcd,ans[gcd]);
        }

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yjt9299/article/details/82081465