zoukankan      html  css  js  c++  java
  • 「6月雅礼集训 2017 Day11」jump

    【题目大意】

    有$n$个位置,每个位置有一个数$x_i$,代表从$i$经过1步可以到达的点在$[max(1, i-x_i), min(i+x_i, n)]$中。

    定义$(i,j)$的距离表示从$i$到$j$经过多少步,从$j$到$i$经过多少步,这两个取最小值。

    求任意两点间最大的距离。

    $1leq n leq 10^5, 1 leq x_i < n$

    【题解】

    每个点经过若干次能过到达的,显然是一个区间。

    考虑倍增,$[L_{x,i}, R_{x,i}]$表示从$x$开始,经过$2^i$步,到达的区间。

    这个可以通过倍增+线段树来解决,线段树维护最小值和最大值,对应区间两个端点。

    对于询问,我们二分答案后,问题转化与是否能找出一个点对步数$> x$($x$为我们二分的值)

    通过倍增我们可以求出每个点经过$x$步后到达的区间,设为$[L', R']$。那么不能到达的就是$[1, L']$和$[R',n]$。

    问题转化为,$[1, L']$和$[R', n]$是否可以经过$x$步以内到达$i$这个点。

    这个可以通过记录一个前缀和以及一个后缀和来解决。

    这里的“和”指的是区间交。

    然后就行啦!

    时间复杂度$O(nlog^3n)$

    upd: 线段树有点问题,已经修正

    =========================分割线=============================

    upd: 之前的复杂度有点问题,是$O(nlog^3n)$的,理论上是过不去的,但是常数太优秀了(逃

    我们可以把二分改为从高位往低位确定答案的每位,每次就不需要倍增了,就在之前的基础上,直接做即可。这样就是$O(nlog^2n)$的了

    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ld;
    
    const int N = 1e5 + 10, M = 2e5 + 10;
    const int inf = 1e9;
    
    # define bit(x, i) (((x) >> (i)) & 1)
    
    int n;
    struct pa {
        int x, y;
        pa() {}
        pa(int x, int y) : x(x), y(y) {}
        friend pa operator + (pa a, pa b) {
            return pa(min(a.x, b.x), max(a.y, b.y));
        }
        friend pa operator - (pa a, pa b) {
            return pa(max(a.x, b.x), min(a.y, b.y));
        }
    };
    
    inline bool out(int x, pa t) {
        return x < t.x || x > t.y;
    }
    
    int L[18][N], R[18][N];
    
    struct SMT {
        pa w[M << 1];
        # define ls (x<<1)
        # define rs (x<<1|1)
        inline void set(int n) {
            for (int i=0; i<=n+n; ++i) w[i] = pa(inf, -inf);
        }
        inline void build(int x, int l, int r, int p) {
            if(l == r) {
                w[x] = pa(L[p][l], R[p][l]);
                return ;
            }
            int mid = l+r>>1;
            build(ls, l, mid, p);
            build(rs, mid+1, r, p);
            w[x] = w[ls] + w[rs];
    //        printf("p = %d, [%d, %d],  [%d, %d]
    ", p, l, r, w[x].x, w[x].y);
        }
        inline pa query(int x, int l, int r, int L, int R) {
            if(L <= l && r <= R) return w[x];
            int mid = l+r>>1;
            if(L > mid) return query(rs, mid+1, r, L, R);
            else if (R <= mid) return query(ls, l, mid, L, R);
            else return query(ls, l, mid, L, mid) + query(rs, mid+1, r, mid+1, R);
        }
        # undef ls
        # undef rs
    }T[18];
    
    // have dis > x
    pa c[N];
    pa t[N];
    pa f[N], g[N];
    
    inline bool chk(int x) {
        pa tmp;
        for (int i=1; i<=n; ++i) {
            tmp.x = t[i].x, tmp.y = t[i].y;
            tmp = T[x].query(1, 1, n, tmp.x, tmp.y);
            c[i] = tmp;
    //        printf("  i = %d, [%d, %d]
    ", i, c[i].x, c[i].y);
        }
        f[1] = c[1]; g[n] = c[n];
        for (int i=2; i<=n; ++i) f[i] = f[i-1] - c[i];
        for (int i=n-1; i; --i) g[i] = g[i+1] - c[i];
        for (int i=1; i<=n; ++i) {
            if(c[i].x == 1 && c[i].y == n) continue;
            // [1, c[i].x-1],  [c[i].y+1], n]
            if(c[i].x != 1) {
                if(out(i, f[c[i].x-1])) return true;
            }
            if(c[i].y != n) {
                if(out(i, g[c[i].y+1])) return true;    
            }
        }
        return false;
    }
    // # include <time.h>
    int main() {
        freopen("jump.in", "r", stdin);
        freopen("jump.out", "w", stdout);
        cin >> n;
        for (int i=0; i<=17; ++i) T[i].set(n);
        for (int i=1, x; i<=n; ++i) {
            scanf("%d", &x);
            L[0][i] = max(i-x, 1);
            R[0][i] = min(i+x, n);
        }
        pa tem;
        for (int j=1; j<=17; ++j) {
            T[j-1].build(1, 1, n, j-1);
            for (int i=1; i<=n; ++i) {
                tem = T[j-1].query(1, 1, n, L[j-1][i], R[j-1][i]);
                L[j][i] = tem.x, R[j][i] = tem.y;
            }
        }
        T[17].build(1, 1, n, 17);
        
    //    for (int j=0; j<=5; ++j) 
    //        for (int i=1; i<=n; ++i) printf("%d %d L = %d, R = %d
    ", i, j, L[j][i], R[j][i]);
        
        int l = 0, r = n-1, mid, ans = 0;
        for (int i=1; i<=n; ++i) t[i] = pa(i, i);
        for (int i=16; ~i; --i) {
            if(chk(i)) {
                for (int j=1; j<=n; ++j) 
                    t[j] = c[j];
                ans += (1<<i);
            }
        }
    
        cout << ans + 1 << endl;
    //    cerr << clock() << " ms
    ";        
        return 0;
    }
    /*
    8
    7 1 1 1 1 1 1 7
    
    10
    2 2 1 2 2 1 2 2 1 2
    */
    View Code

    下面是$O(nlog^3n)$的代码

    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ld;
    
    const int N = 1e5 + 10, M = 2e5 + 10;
    const int inf = 1e9;
    
    # define bit(x, i) (((x) >> (i)) & 1)
    
    int n;
    struct pa {
        int x, y;
        pa() {}
        pa(int x, int y) : x(x), y(y) {}
        friend pa operator + (pa a, pa b) {
            return pa(min(a.x, b.x), max(a.y, b.y));
        }
        friend pa operator - (pa a, pa b) {
            return pa(max(a.x, b.x), min(a.y, b.y));
        }
    };
    
    inline bool out(int x, pa t) {
        return x < t.x || x > t.y;
    }
    
    int L[18][N], R[18][N];
    
    struct SMT {
        pa w[M << 1];
        # define ls (x<<1)
        # define rs (x<<1|1)
        inline void set(int n) {
            for (int i=0; i<=n+n; ++i) w[i] = pa(inf, -inf);
        }
        inline void build(int x, int l, int r, int p) {
            if(l == r) {
                w[x] = pa(L[p][l], R[p][l]);
                return ;
            }
            int mid = l+r>>1;
            build(ls, l, mid, p);
            build(rs, mid+1, r, p);
            w[x] = w[ls] + w[rs];
    //        printf("p = %d, [%d, %d],  [%d, %d]
    ", p, l, r, w[x].x, w[x].y);
        }
        inline pa query(int x, int l, int r, int L, int R) {
            if(L <= l && r <= R) return w[x];
            int mid = l+r>>1;
            if(L > mid) return query(rs, mid+1, r, L, R);
            else if (R <= mid) return query(ls, l, mid, L, R);
            else return query(ls, l, mid, L, mid) + query(rs, mid+1, r, mid+1, R);
        }
        # undef ls
        # undef rs
    }T[18];
    
    // have dis > x
    pa c[N];
    
    pa f[N], g[N];
    
    inline bool chk(int x) {
    //    cout << "x = " << x << endl;
        pa t;
        for (int i=1; i<=n; ++i) {
            t.x = t.y = i;
            for (int j=17; ~j; --j)
                if(bit(x, j)) t = T[j].query(1, 1, n, t.x, t.y);
            c[i] = t;
    //        printf("  i = %d, [%d, %d]
    ", i, c[i].x, c[i].y);
        }
        f[1] = c[1]; g[n] = c[n];
        for (int i=2; i<=n; ++i) f[i] = f[i-1] - c[i];
        for (int i=n-1; i; --i) g[i] = g[i+1] - c[i];
        for (int i=1; i<=n; ++i) {
            if(c[i].x == 1 && c[i].y == n) continue;
            // [1, c[i].x-1],  [c[i].y+1], n]
            if(c[i].x != 1) {
                if(out(i, f[c[i].x-1])) return true;
            }
            if(c[i].y != n) {
                if(out(i, g[c[i].y+1])) return true;    
            }
        }
        return false;
    }
    // # include <time.h>
    int main() {
        freopen("jump.in", "r", stdin);
        freopen("jump.out", "w", stdout);
        cin >> n;
        for (int i=0; i<=17; ++i) T[i].set(n);
        for (int i=1, x; i<=n; ++i) {
            scanf("%d", &x);
            L[0][i] = max(i-x, 1);
            R[0][i] = min(i+x, n);
        }
        pa tem;
        for (int j=1; j<=17; ++j) {
            T[j-1].build(1, 1, n, j-1);
            for (int i=1; i<=n; ++i) {
                tem = T[j-1].query(1, 1, n, L[j-1][i], R[j-1][i]);
                L[j][i] = tem.x, R[j][i] = tem.y;
            }
        }
        T[17].build(1, 1, n, 17);
        
    //    for (int j=0; j<=5; ++j) 
    //        for (int i=1; i<=n; ++i) printf("%d %d L = %d, R = %d
    ", i, j, L[j][i], R[j][i]);
        
        int l = 0, r = n-1, mid, ans;
        while(1) {
            if(r-l <= 3) {
                for (int i=r; i>=l; --i) 
                    if(chk(i)) {
                        ans = i;
                        break;
                    }
                break;
            }
            mid = l+r>>1;
            if(chk(mid)) l = mid;
            else r = mid;
        }
    
        cout << ans + 1 << endl;
    //    cerr << clock() << " ms
    ";        
        return 0;
    }
    /*
    8
    7 1 1 1 1 1 1 7
    
    10
    2 2 1 2 2 1 2 2 1 2
    */
    View Code
  • 相关阅读:
    Web Service接口返回泛型的问题(System.InvalidCastException: 无法将类型为“System.Collections.Generic.List`1[System.String]”的对象强制转换为类型“System.String[]”)
    Asp.net简单代码设置GridView自适应列宽不变形
    iframe自适应高度
    ASP.NET用户控件操作ASPX页面
    C#里面Auotpostback回刷时候,textbox里面的password怎么保存
    CentOS 7在执行yum操作时 报错
    git 查看/修改用户名、密码
    树、二叉树、满二叉树、完全二叉树
    C#中常见的winform控件命名规范 转
    C#控件命名规范
  • 原文地址:https://www.cnblogs.com/galaxies/p/20170627_b.html
Copyright © 2011-2022 走看看