HDU 5869 Different GCD Subarray Query (GCD种类预处理+树状数组维护)

Posted Recoder

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 5869 Different GCD Subarray Query (GCD种类预处理+树状数组维护)相关的知识,希望对你有一定的参考价值。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5869

问你l~r之间的连续序列的gcd种类。

首先固定右端点,预处理gcd不同尽量靠右的位置(此时gcd种类不超过loga[i]种)。

预处理gcd如下代码,感觉真的有点巧妙...

 1         for(int i = 1; i <= n; ++i) {
 2             int x = a[i], y = i;
 3             for(int j = 0; j < ans[i - 1].size(); ++j) {
 4                 int gcd = GCD(x, ans[i - 1][j].first);
 5                 if(gcd != x) {
 6                     ans[i].push_back(make_pair(x, y));
 7                     x = gcd, y = ans[i - 1][j].second;
 8                 }
 9             }
10             ans[i].push_back(make_pair(x, y));
11         }

然后用树状数组维护右端点固定的gcd位置。

 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 = 1e6 + 5;
17 int a[N/10 + 5], bit[N], _pos[N]; //_pos存的是gcd上一次出现的位置
18 vector <P> ans[N/10 + 5]; //存的是以i为右端点的gcd
19 struct query {
20     int l, r, pos;
21     bool operator <(const query& cmp) const {
22         return r < cmp.r;
23     }
24 }q[N/10 + 5];
25 int res[N/10 + 5]; //答案
26 
27 void init(int n) {
28     memset(_pos, 0, sizeof(_pos));
29     memset(bit, 0, sizeof(bit));
30     for(int i = 1; i <= n; ++i) {
31         ans[i].clear();
32     }
33 }
34 
35 int GCD(int a, int b) {
36     return b ? GCD(b, a % b): a;
37 }
38 
39 void add(int i, int x) {
40     for( ; i <= N; i += (i&-i))
41         bit[i] += x;
42 }
43 
44 int sum(int i) {
45     int s = 0;
46     for( ; i >= 1; i -= (i&-i))
47         s += bit[i];
48     return s;
49 }
50 
51 int main()
52 {
53     int n, m;
54     while(scanf("%d %d", &n, &m) != EOF) {
55         init(n);
56         for(int i = 1; i <= n; ++i) {
57             scanf("%d", a + i);
58         }
59         for(int i = 1; i <= m; ++i) {
60             scanf("%d %d", &q[i].l, &q[i].r);
61             q[i].pos = i;
62         }
63         for(int i = 1; i <= n; ++i) {
64             int x = a[i], y = i;
65             for(int j = 0; j < ans[i - 1].size(); ++j) {
66                 int gcd = GCD(x, ans[i - 1][j].first);
67                 if(gcd != x) {
68                     ans[i].push_back(make_pair(x, y));
69                     x = gcd, y = ans[i - 1][j].second;
70                 }
71             }
72             ans[i].push_back(make_pair(x, y));
73         }
74         sort(q + 1, q + m + 1);
75         int p = 1;
76         for(int i = 1; i <= n; ++i) {
77             for(int j = 0; j < ans[i].size(); ++j) {
78                 if(!_pos[ans[i][j].first]) {
79                     add(ans[i][j].second, 1);
80                     _pos[ans[i][j].first] = ans[i][j].second;
81                 } else {
82                     add(_pos[ans[i][j].first], -1);
83                     _pos[ans[i][j].first] = ans[i][j].second;
84                     add(ans[i][j].second, 1);
85                 }
86             }
87             while(i == q[p].r && p <= m) {
88                 res[q[p].pos] = sum(q[p].r) - sum(q[p].l - 1);
89                 ++p;
90             }
91         }
92         for(int i = 1; i <= m; ++i) {
93             printf("%d\n", res[i]);
94         }
95     }
96     return 0;
97 }

 

以上是关于HDU 5869 Different GCD Subarray Query (GCD种类预处理+树状数组维护)的主要内容,如果未能解决你的问题,请参考以下文章

HDU 5869 Different GCD Subarray Query (GCD种类预处理+树状数组维护)

hdu 5869 Different GCD Subarray Query BIT+GCD 2016ICPC 大连网络赛

hdu 5869 区间gcd的求法及应用

hdu 5869 区间不同GCD个数(树状数组)

HDU5869树状数组+gcd预处理

2016大连网络赛 Different GCD Subarray Query