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 }