Ant colony(Codeforces - 474F)
题目来源
https://codeforces.ml/problemset/problem/474/F
题意分析
题目意思的大致可以描述为,给n个数字,组成一个数组。再给出m次询问,每次询问给出要求的区间的左端点和右端点。求该区间内不能整除所有数字的数的个数。
思路分析
一般的区间问题,能首先想到的就是几种树、莫队吧。这里最后想到的是线段树。求该区间内不能整除所有数字的数的个数,满足这样条件的数首先是这个区间里面最小的那个数字吧。但是最小的那个数字不一定就是这个区间所有数字的最大公因数。所以我们要记录区间的最大公因数,最小的数字以及最小的数字的个数。当然,只有当最小的那个数是等于该区间内的最大公因数时,要输出的答案里才不包括这些数字,此时我们用区间数字的个数减去最小数字的个数就是最后的答案。而至于一般情况,如果最小的数字和最大公因数两个不同,那么只能说明该区间内没有能够满足该以上条件的数字,那么答案输出的也就是该区间内数字的个数。
(区间的题目有段时间没写了,确实菜了。。)
code
1 #include <iostream> 2 #include <cstdio> 3 #include <queue> 4 #include <algorithm> 5 #include <cstring> 6 #include <stack> 7 #include <set> 8 #include <cmath> 9 #include <map> 10 11 #define mod 998244353 12 #define INF 0x3f3f3f3f 13 #define ll long long 14 using namespace std; 15 const double eps = 1e-4; 16 const int maxn = 1e5+7; 17 18 struct node{ 19 int v, num, gc; 20 }; 21 22 node tr[maxn * 4]; 23 int a[maxn]; 24 25 int gcd(int a, int b){ 26 return b ? gcd(b, a % b) : a; 27 } 28 29 void build(int l, int r, int x, int &p){ 30 if (l == r){ 31 tr[x].v = a[p]; tr[x].num = 1; tr[x].gc = a[p ++]; 32 return; 33 } 34 int mid = (l + r) >> 1; 35 build(l, mid, x << 1, p); 36 build(mid + 1, r, x << 1 | 1, p); 37 38 tr[x].gc = gcd(tr[x << 1].gc, tr[x<<1|1].gc); 39 if (tr[x << 1].v < tr[x << 1 | 1].v){ 40 tr[x].v = tr[x << 1].v; tr[x].num = tr[x << 1].num; 41 }else if (tr[x << 1].v > tr[x << 1 | 1].v){ 42 tr[x].v = tr[x << 1 | 1].v; tr[x].num = tr[x << 1 | 1].num; 43 }else{ 44 tr[x].v = tr[x << 1 | 1].v; tr[x].num = tr[x << 1].num + tr[x << 1 | 1].num; 45 } 46 } 47 48 void query(int L, int R, int l, int r, int x, int &mv, int &mnum, int &mgc){ 49 if (L <= l && r <= R){ 50 if (mv > tr[x].v){ 51 mv = tr[x].v; mnum = tr[x].num; 52 }else if (mv == tr[x].v) mnum += tr[x].num; 53 mgc = gcd(mgc, tr[x].gc); 54 return; 55 } 56 57 int mid = (l + r) >> 1; 58 if (R > mid) query(L, R, mid + 1, r, x << 1 | 1, mv, mnum, mgc); 59 if (L <= mid) query(L, R, l, mid, x << 1, mv, mnum, mgc); 60 } 61 62 int main(){ 63 int n; scanf("%d", &n); 64 for (int i=1; i<=n; i++) scanf("%d", &a[i]); 65 int t; scanf("%d", &t); 66 int p = 1; 67 build(1, n, 1, p); 68 while (t --){ 69 int l, r; scanf("%d%d", &l, &r); 70 int mv = INF, mnum = 0, mgc = 0; 71 query(l, r, 1, n, 1, mv, mnum, mgc); 72 if (mv != mgc) printf("%d\n", r - l + 1); 73 else printf("%d\n", r - l - mnum + 1); 74 } 75 return 0; 76 }