单调栈——hdu5726 GCD

来源:互联网 发布:网络3d游戏大全 编辑:程序博客网 时间:2024/06/05 18:37

http://acm.hdu.edu.cn/showproblem.php?pid=5726
给一组数字,对于每一个询问l,r
先输出l,r这段区间的区间gcd;
然后输出总区间里有几个区间的gcd等于刚才的gcd;
那么第一问线段树大力维护就好啦;
第二问用单调栈;
因为如果左端点确定的话,我们右端点不断向右移动,那么gcd要么不变,变了的话至少减少一半;
所以其实总共的gcd不会很多;
我们如果能预处理全部都的答案就好了;
所以我们搞一个单调栈,站内元素递增;
我们左端点为1,不断扩展右端点;
对于一个右端点先把栈内的所有元素gcd一波;
然后把栈内的元素合并,最后直接把这个右端点放在栈顶就好了,他一定是最大的;
当然啦,我们每次都要更新每个gcd的个数;

#include<bits/stdc++.h>#define Ll long longusing namespace std;const int N=1e5+5;struct tree{int l,r,v;}T[N*4];map<int,Ll>F;int a[N],q[N],v[N];int n,m,l,r,x,y,ans,t;int gcd(int x,int y){return !y?x:gcd(y,x%y);}void make(int id,int l,int r){    T[id].l=l;T[id].r=r;    if(l==r){T[id].v=a[l];return;}    int mid=l+r>>1;    make(id*2  ,l,mid  );    make(id*2+1,mid+1,r);    T[id].v=gcd(T[id*2].v,T[id*2+1].v);}void out(int id,int x,int y){    if(x<=T[id].l&&T[id].r<=y){        if(!ans)ans=T[id].v;else ans=gcd(T[id].v,ans);        return;    }    if(T[id*2  ].r>=x)out(id*2  ,x,y);    if(T[id*2+1].l<=y)out(id*2+1,x,y);}int find(int x,int y){    ans=0;    out(1,x,y);    return ans; }int main(){    scanf("%d",&t);    int cas=1;    while(t--){        printf("Case #%d:\n",cas++);        scanf("%d",&n);        for(int i=1;i<=n;i++)scanf("%d",&a[i]);        r=0;F.clear();        for(int i=1;i<=n;i++){            for(int j=1;j<=r;j++)q[j]=gcd(q[j],a[i]);            l=0;            for(int j=1;j<=r;j++)                if(q[l]==q[j])v[l]+=v[j];else{                    q[++l]=q[j];                    v[l]=v[j];                }            r=l+1;            q[r]=a[i];            v[r]=1;            for(int j=1;j<=r;j++)F[q[j]]+=v[j];             }        make(1,1,n);        scanf("%d",&m);        while(m--){            scanf("%d%d",&x,&y);            int k=find(x,y);            printf("%d %lld\n",k,F[k]);        }    }}
原创粉丝点击