New Year and Old Subsequence CodeForces - 750E(线段树 + 矩阵)

Posted ruthank

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了New Year and Old Subsequence CodeForces - 750E(线段树 + 矩阵)相关的知识,希望对你有一定的参考价值。

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[ \beginmatrix 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 \endmatrix \right]\]

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

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

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

\[a=\left[ \beginmatrix 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 \endmatrix \right]\]

表示,如果之前有"\(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\n", res >= inf ? -1 : res);
    

以上是关于New Year and Old Subsequence CodeForces - 750E(线段树 + 矩阵)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces 750E New Year and Old Subsequence - 线段树 - 动态规划

New Year and Old Subsequence CodeForces - 750E(线段树 + 矩阵)

Good Bye 2015 B. New Year and Old Property

Codeforces Good Bye 2016 E. New Year and Old Subsequence

Gym611B-New Year and Old Property-简单模拟

Codeforces 750E New Year and Old Subsequence 线段树 + dp (看题解)