cf475D CGCDSSQ

传送门
就是给你n个数字,m次查询,查询gcd为(a_i)的区间有几个

因为是gcd,并且是区间查询,那么考虑(ST)表进行(O(1))查询,而且,在(ST)表里面,gcd是不递增的序列,那么就可以进行二分查找

那么再去考虑对于每一个左区间,查询它的所有右区间的gcd值,考虑到,前一个gcd值肯定是后一个gcd值2倍以上,因为2是最小的素数,那么gcd值就只有(logn)个,即可以考虑二分查找每一个gcd值的右区间即可。

预处理好答案,存放在map里面,时间复杂度(O(nlog^2n)),然后对于每个查询进行(O(1))查询

有关于gcd区间只查询的题,很多情况考虑ST表,而ST表又是单调的,又可以考虑二分

#include <iostream>
#include <cstdio>
#include <cmath>
#include <map>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 1e5 + 5;
int gcd(int a, int b){
    return b == 0 ? a : gcd(b, a % b);
}
namespace ST{
    int st[N][20];
    int lg[N];
    int query(int l, int r){ // 查询区间[l,r]的最值
        int k = lg[r - l + 1];
        return gcd(st[l][k], st[r - (1 << k) + 1][k]);
    }
    void init(int *a, int n){ // 初始化
        for(int i = 1; i <= n; i++) st[i][0] = a[i];
        int k = log2(n / 2) + 1;
        lg[1] = 0;
        for(int i = 2;i <= n; i++) lg[i] = lg[i >> 1] + 1;
        for(int j = 1; j <= k; j++)
            for(int i = 1; i + (1 << j) - 1 <= N; i++)
                st[i][j] = gcd(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
    }
};
int n, a[N];
std::map<int, ll> mp;
int binary_search(int l, int r, int d){
    int left = l;
    for(int i = 1; i <= 100; i++) {
        int mid = (l + r) >> 1;
        if(ST::query(left, mid) >= d) l = mid + 1; 
        else r = mid - 1;
    }
    return (l + r) >> 1;
}
void pre(){
    for(int i = 1; i <= n; i++) {
        int d = a[i], left = i;
        int right = binary_search(i, n, d);
        while(right != n){
            mp[ST::query(i, right)] += right - left + 1;
            left = right + 1;
            d = ST::query(i, right + 1);
            right = binary_search(i, n, d);
        }
        mp[ST::query(i, n)] += right - left + 1;
    }
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    ST::init(a, n);
    int m; scanf("%d", &m);
    pre();
    for(int i = 1; i <= m; i++) {
        int x; scanf("%d", &x);
        printf("%lld
", mp[x]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Emcikem/p/14098109.html