zoukankan      html  css  js  c++  java
  • Button题解

    题面



    solution

    n³dp:fl[x][r]表示当前显示的数字为 x ,还要处理的区间为[x+1,r]时的最小步数,普通区间dp,枚举中间点转移即可,fr类似

    查询的时候也枚举中间点然后左右取max值

    太慢了,把状态定义改为区间进行加速,最后的答案不会很大(45),更改状态为:

    range_l[c,x] = min{l:fr[l][x] <= c}

    range_r[c,x] = max{r:fl[x][r] <= c}

    以range_r为例介绍计算方法:

    要求满足上述条件的最大值,类似n³的枚举一个中点dp方法,可得若range_r[c,x] >= r,则存在一个点mid(中间点),满足range_l[c-dist(x,m)-1][m] <= x + 1 且 range_r[c-dist(x,m)-1][m] >= y,其中dist(x,m)表示从 x 变化到 m 需要的步数,再 -1 是因为询问的代价

    先强制让第一个条件满足,具体做法为从 1 到 max 枚举 x , 每次用 range_l[c-dist(x,m)-1][m] = x + 1 的 m 更新答案,这里是 = 而不是 <= 是因为 x 是从小到大枚举的,之前的已经算过

    对于每一个 m,枚举可以由 m 更新的 x,但复杂度过高,进行折半处理,先把 m 中的 d 为变为 ?,然后对 x 也枚举若干位变成 ? 后的序列更新,复杂度优秀

    对于包含 ? 和数字的序列可以通过 11 进制的方法映射到整型

    code

    #pragma GCC optimize("Ofast")
    #include <bits/stdc++.h>
    using namespace std;
    #define rg register
    void read (int &x) {
        char ch = getchar(); x = 0;
        while (!isdigit(ch)) ch = getchar();
        while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
    }
    const int N = 1e5, M = 2e5;
    int rg_l[50][N], rg_r[50][N], dr[M], dl[M];
    struct qwq {
        int id, val;
        bool operator < (const qwq &x) const {
            return val < x.val;
        }
    } q[6][N + 10];
    int change (int x) {  //把原数字转到带 ? 的映射
        int tmp = 0, t = 1;
        for (int i = 1; i <= 5; ++i)
            tmp += x % 10 * t, x /= 10, t *= 11;
        return tmp;
    }
    int modify (int x, int w) {   //把 x 的第 w 位改为 ? 后映射的数
        int t = 1; for (int i = 1; i < w; ++i) t *= 11;
        return x % t + (x / t - (x / t) % 11 + 10) * t;
    }
    #define Max(a, b) (a = a > b ? a : b)
    #define Min(a, b) (a = a > b ? b : a)
    void dfsr (int c, int x, int now, int w, int s) {
        if (5 - w + 1 < s) return;
        if (w == 6) {
            Max (dr[now], rg_r[c][x]); return;
        } dfsr (c, x, now, w + 1, s);
        if (s) dfsr (c, x, modify (now, w), w + 1, s - 1);
    }
    void dfsl (int c, int x, int now, int w, int s) {
        if (5 - w + 1 < s) return;
        if (w == 6) {
            Min (dl[now], rg_l[c][x]); return;
        } dfsl (c, x, now, w + 1, s);
        if (s) dfsl (c, x, modify (now, w), w + 1, s - 1);
    }
    void workr (int c, int x, int now, int w) {
        if (w == 6) {
            Max (rg_r[c][x], dr[now]); return;
        } workr (c, x, now, w + 1);
        workr (c, x, modify (now, w), w + 1);
    }
    void workl (int c, int x, int now, int w) {
        if (w == 6) {
            Min (rg_l[c][x], dl[now]); return;
        } workl (c, x, now, w + 1);
        workl (c, x, modify (now, w), w + 1);
    }
    void Pre_work() {
        memset (rg_l, 0x3f, sizeof (rg_l));
        for (int i = 0; i < N; ++i) {
            rg_l[0][i] = rg_l[1][i] = max (0, i - 1);
            rg_r[0][i] = rg_r[1][i] = min (i + 1, N - 1);
        }
        for (int i = 2; i <= 45; ++i) {
            memset (dr, 0, sizeof (dr));
            memset (dl, 0x3f, sizeof (dl));
            for (int p = 1; p <= 5 && p < i; ++p) {
                for (int x = 0; x < N; ++x)
                    q[p][x] = (qwq) {x, rg_l[i - p - 1][x]};
              sort (q[p], q[p] + N);
           } int y[6];
           y[1] = y[2] = y[3] = y[4] = y[5] = 0;
            for (int x = 0; x < N; ++x) {
                for (int p = 1; p <= 5 && p < i; ++p) {
                    while (y[p] < N && q[p][y[p]].val < x + 1) ++y[p];
                    while (y[p] < N && q[p][y[p]].val == x + 1) {
                        dfsr (i - p - 1, q[p][y[p]].id, change (q[p][y[p]].id), 1, p), ++y[p];
                    }
                }
                workr (i, x, change (x), 1);
            }
            //////////////////////////////////////////////////////////
            for (int p = 1; p <= 5 && p < i; ++p) {
                for (int x = 0; x < N; ++x)
                    q[p][x] = (qwq) {x, rg_r[i - p - 1][x]};
              sort (q[p], q[p] + N);
            }
            y[1] = y[2] = y[3] = y[4] = y[5] = N - 1;
            for (int x = N - 1; x >= 0; --x) {
                for (int p = 1; p <= 5 && p < i; ++p) {
                    while (y[p] >= 0 && q[p][y[p]].val > x - 1) --y[p];
                    while (y[p] >= 0 && q[p][y[p]].val == x - 1) {
                        dfsl (i - p - 1, q[p][y[p]].id, change (q[p][y[p]].id), 1, p), --y[p];
                    }
                }
                workl (i, x, change (x), 1);
            }
        }
    }
    int get_dis (int x, int y) {
        int tmp = 0;
        for (int i = 1; i <= 5; ++i)
            tmp += (x % 10 != y % 10), x /= 10, y /= 10;
        return tmp;
    }
    void solve (int l, int r) {
        int res = 1e9;
        for (int mid = l; mid <= r; ++mid) {
            int co = get_dis (0, mid) + 1;
            int cl = 0, cr = 0;
            while (rg_l[cl][mid] > l) ++cl;
            while (rg_r[cr][mid] < r) ++cr;
            Min (res, co + max (cl, cr));
        } printf ("%d
    ", res);
    }
    signed main() {
        freopen ("button.in", "r", stdin);
        freopen ("button.out", "w", stdout);
        Pre_work(); int m, l, r; read (m);
        while (m--) read (l), read (r), solve (l, r);
        return 0;
    }
    
  • 相关阅读:
    Could not determine which “make” command to run. Check the “make” step in the build configuration
    crontab定时任务不执行的原因
    Linux 设置定时任务crontab命令
    Runtime.getRuntime.exec()执行linux脚本导致程序卡死问题
    Java并发编程:volatile关键字解析
    什么是ClassLoader
    GeoJson格式与转换(shapefile)Geotools
    Docker图形化工具——Portainer
    Docker安装mysql、nginx、redis、tomcat
    Docker中nginx+tomcat实现负载均衡
  • 原文地址:https://www.cnblogs.com/whx666/p/Button.html
Copyright © 2011-2022 走看看