zoukankan      html  css  js  c++  java
  • BZOJ 5325 [Jsoi2017]码农 题解

    有一个很显然的 DP, 设 (f[i]) 表示前 (i) 考虑完了前 (i) 个字符的最小代价.

    有两种转移:

    • (f[i]=f[i-1]+c[s_i]).
    • (f[i]=min_{d_i-1le j<i}{f[j]+calc(j+1,i)}).

    (d_i) 为最小的满足 (([d_i,i])([1,d_{i}-1]) 的子串) 的位置, 可以用 SAM 预处理出来.
    具体来说, 将字符 (s_i) 依次加入, 维护一个指针表示当前最大的 (p) 使得 ([i+1,p])([1,i]) 的子串.

    然后发现第 2 种转移可以用单调队列优化, 就完了. 复杂度为 (O(N)).

    </:>

    #include <bits/stdc++.h>
    #define N 202200
    using namespace std;
    int sze, las, lnk[N << 1], len[N << 1], nxt[N << 1][10];
     
    void extend(int c) {
        int cur = ++sze, p; cur[len] = las[len] + 1;
        for (p = las; p && !nxt[p][c]; p = lnk[p])
            nxt[p][c] = cur;
        if (!p) lnk[cur] = 1;
        else {
            int q = nxt[p][c];
            if (len[q] == len[p] + 1) lnk[cur] = q;
            else {
                int cln = ++sze; cln[len] = p[len] + 1;
                memcpy(nxt[cln], nxt[q], sizeof nxt[q]);
                lnk[cln] = lnk[q], lnk[q] = lnk[cur] = cln;
                for (; p && nxt[p][c] == q; p = lnk[p])
                    nxt[p][c] = cln;
            }
        } las = cur;
    }
     
    int n, a, b, c[12], d[N];
    long long f[N];
    char s[N];
     
    inline int go(int p, int ch, int le) {
        while (p != 1 && !nxt[p][ch])
            p = lnk[p], le = len[p];
        if (nxt[p][ch]) p = nxt[p][ch], ++le;
        return le;
    }
     
    int main() {
        scanf("%s", s + 1);
        n = strlen(s + 1);
        for (int i = 0; i <= 9; ++i)
            scanf("%d", c + i);
        cin >> a >> b;
     
        las = sze = 1;
        int p = 1, t = 0, le = 0;
        for (int i = 1, j = 1; i <= n; ++i) {
            extend(s[i] - '0');
            while (t < n && go(p, s[t + 1] - '0', le) >= t + 1 - i) {
                int ch = s[++t] - '0';
                while (p != 1 && !nxt[p][ch])
                    le = len[p = lnk[p]];
                if (nxt[p][ch]) p = nxt[p][ch], ++le;
            }
            while (j <= t) d[j++] = i + 1;
        }
     
        static int q[N], ql = 1, qr = 0;
        for (int i = 1; i <= n; ++i) {
            f[i] = f[i - 1] + c[s[i] - '0'];
            while (ql <= qr && q[ql] < d[i] - 1) ++ql;
            if (ql <= qr) {
                int j = q[ql];
                f[i] = min(f[i], f[j] + 1ll * a * (i - j) + b);
            }
            while (ql <= qr && (f[i] - 1ll * a * i) <= (f[q[qr]] - 1ll * a * q[qr])) --qr;
            q[++qr] = i;
        }
     
        cout << f[n] << endl;
     
        return 0;
    }
    
  • 相关阅读:
    OCP-1Z0-052-V9.02-177题
    游戏服务端IOCP模型,自己封装的一个类,3行代码搞定服务端。
    OCP-1Z0-052-V9.02-116题
    OCP-1Z0-052-V9.02-72题
    map按value值查找——find_if的使用
    Oracle OCP 11G 052答案解析目录
    Oracle OCP 11G 052 V8.02与V9.02版本对比
    OCP-1Z0-052-V8.02-102题
    OCP-1Z0-052-V8.02-117题
    在完成端口IOCP模型判断客户端是否已关闭连接(掉线)
  • 原文地址:https://www.cnblogs.com/hnfms-jerry/p/solution_bzoj5325.html
Copyright © 2011-2022 走看看