gcd区间

https://vjudge.net/contest/237352#problem/A

题意:给出n个数,q个询问,对于每个询问xi,求有多少个子区间,区间内的gcd为xi,分别输出个数。

解法:一段区间,每在末尾增加一个数,区间gcd要么保持原状,要么至少缩小为原来的一半,所以对于1e9的数,区间不同的gcd值至多有log(1e9)个。

枚举右区间,对于每个右区间(i,r),用map存区间(1,r), (2,r) ... (r,r) 的gcd值,又知map的大小不超过100。每次右区间增加1,就可以通过r-1的map得到r的map,更新map,更新答案,如此类推,右区间从1枚举至n。

 1 #include <bits/stdc++.h>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cstdio>
 5 #include <cstring>
 6 #include <string>
 7 #include <cmath>
 8 #include <cstdlib>
 9 #include <queue>
10 #include <stack>
11 #include <map>
12 #include <vector>
13 #include <set>
14 #include <bitset>
15 #include <iomanip>
16 #define ms(a, b) memset(a, b, sizeof(a));
17 using namespace std;
18 typedef long long LL;
19 typedef pair<int, int> pii;
20 const int INF = 0x3f3f3f3f;
21 const int maxn = 1e2 + 10;
22 const int MAXN = 2e4 + 10;
23 const double eps = 1e-8;
24 const int mod = 1e9 + 7;
25 int n, q;
26 map<int, int> cnt1, cnt2;
27 map<int, LL> ans;
28 
29 int gcd(int a, int b) {
30     return b == 0 ? a : gcd(b, a % b);
31 }
32 
33 int main()
34 {
35 #ifdef local
36     freopen("case.in","r",stdin);
37 //    freopen("out.in","w",stdout);
38 #endif
39     scanf("%d", &n);
40     for(int i = 0; i < n; i++) {
41         int a;
42         scanf("%d", &a);
43         map<int, int>::iterator it;
44         for(it = cnt1.begin(); it != cnt1.end(); it++) {
45             cnt2[gcd(a, it->first)] += cnt1[it->first];
46         }
47         cnt2[a]++;
48         cnt1 = cnt2;
49         cnt2.clear();
50         for(it = cnt1.begin(); it != cnt1.end(); it++)
51             ans[it->first] += cnt1[it->first];
52     }
53     scanf("%d", &q);
54     for(int i = 0; i < q; i++) {
55         int x;
56         scanf("%d", &x);
57         printf("%lld\n", ans[x]);
58     }
59     return 0;
60 }

猜你喜欢

转载自www.cnblogs.com/Sissi-hss/p/9471713.html
gcd