zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    python读写操作(txt, mat, xls, etc文件)
    开发linux版QQ就是支持未来的国产操作系统
    为知笔记linux绿色版的快速调用
    数学物理中的常见误区
    markdown语法小结
    信息爆炸时代的知识获取
    matlab: 数据的读写
    APS期刊投稿准备: REVTex格式
    markdown基本语法
    常见的数学关系
  • 原文地址:https://www.cnblogs.com/Emcikem/p/14098109.html
Copyright © 2011-2022 走看看