HDU 5726 GCD(DP)

 

【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=5726

 

【题目大意】

  给出数列An,对于询问的区间【L,R】,求出区间内数的GCD值,并且求出GCD值与其相等的区间总数

 

【题解】

  首先,固定一个区间的右端点,利用GCD的递减性质,可以求出GCD相等的区间左端点的范围,将其范围的左右端点保存下来,同时,对于每个新产生的区间,以其GCD值为下标的MAP值+1,最后对于每个询问,在其右端点保存的范围中查找,获得其GCD值,同时在MAP中获取该GCD值对应的区间总数,输出即可。

 

【代码】

#include <map>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
map<int,long long> M;
const int N=100005;
int Gcd,n,l[N],v[N],len[N],T,j,q,L,R,Cas,a[N];
struct data{int l,v;}p[N][50];
int gcd(int x,int y){return __gcd(x,y);}
int main(){
    scanf("%d",&T);
    while(T--){
        printf("Case #%d:\n",++Cas);
        M.clear();
        scanf("%d",&n);
        memset(len,0,sizeof(len));
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)for(v[i]=a[i],j=l[i]=i;j;j=l[j]-1){
            v[j]=gcd(v[j],a[i]);
            while(l[j]>1&&gcd(a[i],v[l[j]-1])==gcd(a[i],v[j]))l[j]=l[l[j]-1];
            p[i][len[i]].l=l[j];p[i][len[i]++].v=v[j];
            M[v[j]]+=(j-l[j]+1);
        }scanf("%d",&q);
        while(q--){
            scanf("%d%d",&L,&R);
            for(int i=0;i<len[R];i++){
                if(L>=p[R][i].l){Gcd=p[R][i].v;break;}
            }printf("%d %lld\n",Gcd,M[Gcd]);
        }
    }return 0;
}

  

posted @ 2016-11-16 12:55  forever97  阅读(380)  评论(0编辑  收藏  举报