GCD (hdu 5726)
GCD
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1497 Accepted Submission(s): 483
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.
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).
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
思路:RMQ+二分
一开始我用的线段树去维护各个区间的gcd但是超时,并且我没有优化。
暴力统计的各个区间的gcd;
后来发现gcd的性质,也就是求数的gcd,这些数的个数越多那么gcd越小,所以从左到右,以某个端点开始的gcd的大小随着区间增大而减小,那么二分统计以某个点为端点的gcd
最多每个端点二分30次。
然后还是超时。
然后改用RMQ基于稀疏表的,查询O(n);
复杂度(n*log(n));
1 #include<stdio.h> 2 #include<algorithm> 3 #include<iostream> 4 #include<string.h> 5 #include<stdlib.h> 6 #include<queue> 7 #include<map> 8 #include<math.h> 9 using namespace std; 10 typedef long long LL; 11 int RMQ[20][100005]; 12 int ans[100005]; 13 map<int,LL>my; 14 int gcd(int n,int m) 15 { 16 if(m==0) 17 return n; 18 else if(n%m==0) 19 { 20 return m; 21 } 22 else return gcd(m,n%m); 23 } 24 int main(void) 25 { 26 int i,j,k; 27 int n,m; 28 scanf("%d",&k); 29 int ca=0; 30 while(k--) 31 { 32 my.clear(); 33 scanf("%d",&n); 34 for(i=1; i<=n; i++) 35 { 36 scanf("%d",&ans[i]); 37 } 38 for(i=1; i<=n; i++) 39 { 40 RMQ[0][i]=ans[i]; 41 } 42 scanf("%d",&m); 43 for(i=1; i<20; i++) 44 { 45 for(j=1; j<=n; j++) 46 { 47 if(j+(1<<i)-1<=n) 48 { 49 RMQ[i][j]=gcd(RMQ[i-1][j],RMQ[i-1][j+(1<<(i-1))]); 50 } 51 } 52 } 53 for(i=1; i<=n; i++) 54 { 55 for(j=i; j<=n;) 56 { 57 int t=log2(j-i+1); 58 int ac=gcd(RMQ[t][i],RMQ[t][j-(1<<t)+1]); 59 int l=j; 60 int r=n; 61 int id=0; 62 while(l<=r) 63 { 64 int mid=(l+r)/2; 65 int c=log2(mid-i+1); 66 int ak=gcd(RMQ[c][i],RMQ[c][mid-(1<<c)+1]); 67 if(ak>=ac) 68 { 69 id=mid; 70 l=mid+1; 71 } 72 else r=mid-1; 73 } 74 my[ac]+=id-j+1; 75 j=id+1; 76 } 77 } 78 printf("Case #%d:\n",++ca); 79 while(m--) 80 { 81 int x,y; 82 scanf("%d %d",&x,&y); 83 if(x>y) 84 { 85 swap(x,y); 86 } 87 int ct=log2(y-x+1); 88 int acc=gcd(RMQ[ct][x],RMQ[ct][y-(1<<ct)+1]); 89 printf("%d %lld\n",acc,my[acc]); 90 } 91 } 92 return 0; 93 }
油!油!you@