HDOJ 5726 GCD(RMQ+二分)
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
Sample Output
题意:
有N个数,求第L个数到第R个数的最大公约数,并且求出任意区间内最大公约数为ans的数量。
题解:
对于区间[L,R],如果L固定不变,R不断右移时,gcd的值在不断下降,而且每次下降的幅度都不小于一半。我们只要枚举左端点L,然后二分L到N的区间,找到最大公约数为gcd的最大区间,记录这个gcd的数量并更新到map中即可。
#include<iostream> #include<algorithm> #include<cmath> #include<map> using namespace std; typedef long long ll; const int MAX=100005; int dp[MAX][20]; int mm[MAX]; ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} void initrmq(int n,int b[]) { mm[0]=-1; for(int i=1;i<=n;i++) { mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1]; dp[i][0]=b[i]; } for(int j=1;j<=mm[n];j++) for(int i=1;i+(1<<j)-1<=n;i++) dp[i][j]=gcd(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } ll rmq(int x,int y) { int k=mm[y-x+1]; return gcd(dp[x][k],dp[y-(1<<k)+1][k]); } ll find(int l,int r) { int k=(int)log2((double)(r-l+1)); return gcd(dp[l][k], dp[r-(1<<k)+1][k]); } map<int,long long>ma; int main() { ios::sync_with_stdio(false); int T,n,ca=1,i,j; cin>>T; while(T--) { ma.clear(); int b[MAX]; cin>>n; for(i=1;i<=n;i++) cin>>b[i]; initrmq(n,b); for(i=1;i<=n;i++) { int I=i; ll now=b[i]; while(I!=n+1) { int preI=I,N=n; while(I!=N) { int mid=(I+N)/2+1; if(find(I,mid)==now) I=mid; else N=mid-1; } ma[now]+=N-preI+1ll; I++; if(I!=n+1) now=gcd(now,b[I]); } } cout<<"Case #"<<ca++<<":"<<endl; int q; cin>>q; for(i=1;i<=q;i++) { int l,r; cin>>l>>r; ll ans=rmq(l,r); cout<<ans<<" "<<ma[ans]<<endl; } } return 0; }