zoukankan      html  css  js  c++  java
  • 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);
        }
    }
    
  • 相关阅读:
    向现有的磁盘组加入/删除ASM磁盘
    词语相似度计算
    C++ STL algorithm 列表
    ORACLE内核参数
    一款好的UI草图设计软件
    (转)svn检出的时候报 Unable to connect to a repository at URL错误
    HTTP 错误 500.19 – Internal Server Error web.config 文件的 system.webServer/httpErrors 节中不允许绝对物理路径“C:\inetpub\custerr”。
    使用SVN后系统变慢的解决方法
    oracle 11g ORA12541: TNS: 无监听程序 (DBD ERROR: OCIServerAttach)
    [转载]无法删除oci.dll文件的解决办法
  • 原文地址:https://www.cnblogs.com/ruthank/p/11506185.html
Copyright © 2011-2022 走看看