题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5726
题意:给定数列,求区间[L,R]的GCD的值,并求出有多少个子区间满足和[L,R]的GCD相等。
RMQ预处理所有区间的GCD,枚举所有区间的左边界i,起初固定右边界j,二分枚举右边界j的最大值,使得[i,j]区间内的GCD不变,更新对应GCD的值,大小为j-i。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 const int maxn = 100100; 6 int n, q; 7 LL a[maxn]; 8 LL dp[maxn][30]; 9 map<LL, LL> cnt; 10 11 LL gcd(LL x, LL y) { 12 return y == 0 ? x : gcd(y, x%y); 13 } 14 15 void st() { 16 for(int i = 1; i <= n; i++) dp[i][0] = a[i]; 17 for(int j = 1; (1 << j) <= n; j++) { 18 for(int i = 1; i + (1 << j) - 1 <= n; i++) { 19 dp[i][j] = gcd(dp[i][j-1], dp[i+(1<<(j-1))][j-1]); 20 } 21 } 22 } 23 24 LL query(int l, int r) { 25 int j = 0; 26 while(1 << (j + 1) <= r - l + 1) j++; 27 return gcd(dp[l][j], dp[r-(1<<j)+1][j]); 28 } 29 30 inline bool scan_d(LL &num) { 31 char in;bool IsN=false; 32 in=getchar(); 33 if(in==EOF) return false; 34 while(in!='-'&&(in<'0'||in>'9')) in=getchar(); 35 if(in=='-'){ IsN=true;num=0;} 36 else num=in-'0'; 37 while(in=getchar(),in>='0'&&in<='9'){ 38 num*=10,num+=in-'0'; 39 } 40 if(IsN) num=-num; 41 return true; 42 } 43 44 int main() { 45 //freopen("in", "r", stdin); 46 int T, _ = 1; 47 scanf("%d", &T); 48 int l, r; 49 while(T--) { 50 scanf("%d", &n); 51 for(int i = 1; i <= n; i++) { 52 scan_d(a[i]); 53 } 54 st(); cnt.clear(); 55 for(int i = 1; i <= n; i++) { 56 int j = i; 57 while(j <= n) { 58 LL cur = query(i, j); 59 int lo = j, hi = n; 60 while(lo <= hi) { 61 int mid = (lo + hi) >> 1; 62 if(query(i, mid) >= cur) lo = mid + 1; 63 else hi = mid - 1; 64 } 65 cnt[cur] += (LL)(hi - j + 1); 66 j = hi + 1; 67 } 68 } 69 printf("Case #%d: ", _++); 70 scanf("%d", &q); 71 while(q--) { 72 scanf("%d %d", &l, &r); 73 LL ret = query(l, r); 74 cout << ret << " " << cnt[ret] << endl; 75 } 76 } 77 return 0; 78 }