zoukankan      html  css  js  c++  java
  • 多校hdu5726 线段树+预处理

    第一问是没有修改的线段树,第二问暴力预处理,因为gcd的结果不会很多

    在预处理阶段需要把每个区间的gcd相等的数量储存起来(用map容器),在一个序列例如:12467,枚举左区间L直到n此处时间为O(n),l=1时寻找右区间随着r的增大gcd单调不增,在某个区域内gcd相等想到用二分查找时间是O(logn),再加上线段树查找用到时间O(logn),总时间是O(n*logn*longn)会超时,所以需要更优。

    解决办法:左区间固定时利用线段树找到gcd减小的区间,从l到gcd减小的区间gcd相等。

    #include<map>
    #include<stdio.h>
    #include<string>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define  LL long long
    const int N = 4e5 + 10;
    int T, n, m, g[N], a[N], l, r, q, cas = 0;
    map<int, LL> M;
    int gcd(int x, int y) { return x%y ? gcd(y, x%y) : y; }
    void build(int x, int l, int r)
    {
        if (l == r) scanf("%d", &g[x]), a[l] = g[x];
        else
        {
            int mid = l + r >> 1;
            build(x << 1, l, mid);
            build(x << 1 | 1, mid + 1, r);
            g[x] = gcd(g[x << 1], g[x << 1 | 1]);
        }
    }
    
    int get(int x, int l, int r, int ll, int rr)
    {
        if (ll <= l&&r <= rr) return g[x];
        int mid = l + r >> 1;
        int x1 = 0, x2 = 0;
        if (ll <= mid) x1 = get(x << 1, l, mid, ll, rr);
        if (rr > mid) x2 = get(x << 1 | 1, mid + 1, r, ll, rr);
        return gcd(min(x1, x2), max(x1, x2));
    }
    
    bool find(int x, int l, int r, int ll, int rr, int u, int &v)
    {
        if (ll <= l && r <= rr)
        {
            if (gcd(v, g[x]) < u)
            {
                if (l == r)
                {
                    q = l; return true;
                }
                else
                {
                    int mid = l + r >> 1;
                    if (find(x<<1, l, mid, ll, rr, u, v)) return true;
                    if (find(x<<1|1, mid + 1, r, ll, rr, u, v)) return true;
                }
            }
            else { v = gcd(v, g[x]); return false; }
        }
        else
        {
            int mid = l + r >> 1;
            if (ll <= mid&&find(x<<1, l, mid, ll, rr, u, v)) return true;
            if (rr > mid&& find(x<<1|1, mid + 1, r, ll, rr, u, v)) return true;
            return false;
        }
    }
    
    int main()
    {
        scanf("%d", &T);
        while (T--)
        {
            M.clear();
            scanf("%d", &n);
            build(1, 1, n);
            for (int i = 1, j, k; i <= n; i++)
            {
                int kk = get(1, 1, n, i, n);
                for (k = i, j = a[i]; k <= n;)
                {
                    if (kk == j) { M[j] += n - k + 1; break; }
                    int gg = a[i];
                    find(1, 1, n, i, n, j, gg);
                    M[j] += q - k;
                    k = q;    j = gcd(a[q], j);
                }
            }
            scanf("%d", &m);
            printf("Case #%d:
    ", ++cas);
            while (m--)
            {
                scanf("%d%d", &l, &r);
                int x = get(1, 1, n, l, r);
                printf("%d %lld
    ", x, M[x]);
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    MariaDB的安装与启动
    Win10系统提示对于目标文件系统过大
    kvm中重命名虚拟机
    libvirt启动报错Failed to start Virtualization daemon
    常用的一些开源小工具 之 日期时间类
    常用的一些开源小工具 之 StringUtils
    zookeeper之 watch机制(三)
    shiro权限框架使用详解
    zookeeper节点之 java操作 和zookeeper-权限(ACL),设置超级用户(二)
    时间处理Date,最好改成 LocalDateTime ,时间计算,格式化时间,增加减少时间
  • 原文地址:https://www.cnblogs.com/yuanbo123/p/5704404.html
Copyright © 2011-2022 走看看