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; }
愿你出走半生,归来仍是少年