Codeforces Round #271 (Div. 2) F. Ant colony (RMQ or 线段树)

题目链接: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\n", r - l + 1 - query(1 , l , r , g));
88     }
89     return 0;
90 }

 

posted @ 2016-07-27 17:35  Recoder  阅读(128)  评论(0编辑  收藏  举报