New Year and Old Subsequence CodeForces

New Year and Old Subsequence (CodeForces - 750E)

题意:

给出一个长度为(N)的数字串,(q)次询问。每次询问一段区间。在区间内删除尽量少的字符,使得区间内含有序列"(2017)",且不含有"(2016)"。

(n,q<=200000)

题解:

(01234)五种状态分别表示""、 "(2)"、"(20)"、"(201)"、"(2017)"。

设矩阵(M[5][5])(M[i][j])表示从状态(i)转移到(j)需要删除的最少字符数量。

例如,('2')可以把状态(0)转移到状态(1),所以矩阵就是

[a=left[ egin{matrix} 1 & 0 & inf & inf & inf \ inf & 0 & inf & inf & inf \ inf & inf & 0 & inf & inf \ inf & inf & inf & 0 & inf \ inf & inf & inf & inf & 0 end{matrix} ight]]

代表,如果我们删去这个('2'),维持本来的状态(0),花费就是(1)。如果不删,那么状态(0)就可以转移到状态(1),所以(a[0][1] = 0)

对于('0' '1' '7')同理可构造类似的矩阵。

对于('6'),可以构造如下矩阵

[a=left[ egin{matrix} 0 & inf & inf & inf & inf \ inf & 0 & inf & inf & inf \ inf & inf & 0 & inf & inf \ inf & inf & inf & 1 & inf \ inf & inf & inf & inf & 1 end{matrix} ight]]

表示,如果之前有"(201)" 或者 "(2017)",这个('6')就需要删除。否则就不用删除。

对于两个矩阵的合并,我们只要像(Floyd)算法那样,枚举转移就可以了。

因为矩阵的状态转移是满足结合律的,所以用线段树维护区间,就可以多组查询了。

以后再遇到区间上的状态转移,可以尝试用这种方法瞎搞一搞。

代码

#include <bits/stdc++.h>
#define fopi freopen("in.txt", "r", stdin)
#define fopo freopen("out.txt", "w", stdout)
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5 + 10;
typedef long long LL;

char s[maxn];

struct Matrix {
    int m[5][5];
    Matrix() { memset(m, 0x3f, sizeof(m)); }
    Matrix operator * (const Matrix &rhs) {
        Matrix res;
        for (int k = 0; k <= 4; k++)
        for (int i = 0; i <= 4; i++)
        for (int j = 0; j <= 4; j++)
            res.m[i][j] = min(res.m[i][j], m[i][k] + rhs.m[k][j]);
        return res;
    }
};

struct SegTree {
    struct Node {
        int l, r;
        Matrix M;
    }t[maxn * 4];

    void build(int id, int l, int r) {
        t[id].l = l, t[id].r = r;
        if (l == r) {
            for (int i = 0; i <= 4; i++) t[id].M.m[i][i] = 0;
            if (s[l] == '2') { t[id].M.m[0][0] = 1; t[id].M.m[0][1] = 0; }
            if (s[l] == '0') { t[id].M.m[1][1] = 1; t[id].M.m[1][2] = 0; }
            if (s[l] == '1') { t[id].M.m[2][2] = 1; t[id].M.m[2][3] = 0; }
            if (s[l] == '7') { t[id].M.m[3][3] = 1; t[id].M.m[3][4] = 0; }
            if (s[l] == '6') { t[id].M.m[3][3] = 1; t[id].M.m[4][4] = 1; }
            return;
        }
        int mid = (l+r) / 2;
        build(id*2, l, mid);
        build(id*2+1, mid+1, r);
        t[id].M = t[id*2].M * t[id*2+1].M;
    }

    Matrix query(int id, int l, int r) {
        if (l <= t[id].l && r >= t[id].r) return t[id].M;
        int mid = (t[id].l + t[id].r) / 2;
        if (r <= mid) return query(id*2, l, r);
        else if (l > mid) return query(id*2+1, l, r);
        return query(id*2, l, mid) * query(id*2+1, mid+1, r);
    }
}T;

int l, r, n, q;
int main() {
    //fopi;
    scanf("%d%d", &n, &q);
    scanf("%s", s+1);
    T.build(1, 1, n);
    for (int i = 1; i <= q; i++) {
        scanf("%d%d", &l, &r);
        int res = T.query(1, l, r).m[0][4];
        printf("%d
", res >= inf ? -1 : res);
    }
}
原文地址:https://www.cnblogs.com/ruthank/p/11506185.html