题目链接:http://codeforces.com/contest/474/problem/F
题意简而言之就是问你区间l到r之间有多少个数能整除区间内除了这个数的其他的数,然后区间长度减去数的个数就是答案。
要是符合条件的话,那这个数的大小一定是等于gcd(a[l]...a[r])。
我们求区间gcd的话,既可以利用线段树性质区间递归下去然后返回求解,但是每次查询是log的,所以还可以用RMQ,查询就变成O(1)了。
然后求解区间内有多少个数的大小等于gcd的话,也是利用线段树的性质,区间递归求解之,复杂度也是log的。
1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cstdio> 7 #include <vector> 8 #include <cmath> 9 #include <ctime> 10 #include <list> 11 #include <set> 12 #include <map> 13 using namespace std; 14 typedef long long LL; 15 typedef pair <int, int> P; 16 const int N = 1e5 + 5; 17 int gcd[N][20]; 18 struct SegTree { 19 int l , r , Min , num; 20 }T[N << 3]; 21 22 int GCD(int a, int b) { 23 return b ? GCD(b, a % b) : a; 24 } 25 26 void ST(int n) { 27 for(int k = 1; k < 20; ++k) { 28 for(int i = 1; i + (1 << k) - 1 <= n; ++i) { 29 gcd[i][k] = GCD(gcd[i][k - 1], gcd[i + (1 << (k - 1))][k - 1]); 30 } 31 } 32 } 33 34 void build(int p , int l , int r) { 35 int mid = (l + r) >> 1; 36 T[p].l = l , T[p].r = r , T[p].num; 37 if(l == r) { 38 T[p].Min = gcd[l][0]; 39 T[p].num = 1; 40 return ; 41 } 42 build(p << 1 , l , mid); 43 build((p << 1)|1 , mid + 1 , r); 44 if(T[p << 1].Min == T[(p << 1)|1].Min) { 45 T[p].Min = T[p << 1].Min; 46 T[p].num = T[p << 1].num + T[(p << 1)|1].num; 47 } 48 else if(T[p << 1].Min < T[(p << 1)|1].Min) { 49 T[p].Min = T[p << 1].Min; 50 T[p].num = T[p << 1].num; 51 } 52 else { 53 T[p].Min = T[(p << 1)|1].Min; 54 T[p].num = T[(p << 1)|1].num; 55 } 56 } 57 58 int query(int p , int l , int r , int g) { 59 int mid = (T[p].l + T[p].r) >> 1; 60 if(T[p].l == l && T[p].r == r) { 61 return T[p].Min == g ? T[p].num : 0; 62 } 63 if(r <= mid) { 64 return query(p << 1 , l , r , g); 65 } 66 else if(l > mid) { 67 return query((p << 1)|1 , l , r , g); 68 } 69 else { 70 return query(p << 1 , l , mid , g) + query((p << 1)|1 , mid + 1 , r , g); 71 } 72 } 73 74 int main() 75 { 76 int n, q, l, r; 77 scanf("%d", &n); 78 for(int i = 1; i <= n; ++i) 79 scanf("%d", &gcd[i][0]); 80 ST(n); 81 build(1 , 1 , n); 82 scanf("%d", &q); 83 while(q--) { 84 scanf("%d %d", &l, &r); 85 int k = log2(r - l + 1); 86 int g = GCD(gcd[l][k], gcd[r - (1 << k) + 1][k]); 87 printf("%d ", r - l + 1 - query(1 , l , r , g)); 88 } 89 return 0; 90 }