Codeforces750E. New Year and Old Subsequence (线段树维护DP)

题意:长为2e5的数字串 每次询问一个区间 求删掉最少几个字符使得区间有2017子序列 没有2016子序列

   不合法输出-1

题解:dp i,p(0-4)表示第i个数匹配到2017的p位置删掉的最少数

   每次转移的状态可以用一个5X5的矩阵维护 所以用线段树维护一段连续的状态

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;

int n, m;
char s[MAXN];
struct node {
    int c[5][5];
};

node add(node x, node y) {
    node res;
    for(int i = 0; i < 5; i++)
    for(int j = 0; j < 5; j++) {
        res.c[i][j] = MAXN;
        for(int k = 0; k < 5; k++)
            res.c[i][j] = min(res.c[i][j], x.c[i][k] + y.c[k][j]);
    }
    return res;
}

node sum[MAXN << 2];
void build(int l, int r, int rt) {
    if(l == r) {
        for(int i = 0; i < 5; i++)
        for(int j = 0; j < 5; j++) sum[rt].c[i][j] = (i == j) ? 0 : MAXN;

        if(s[l] == '2') sum[rt].c[0][1] = 0, sum[rt].c[0][0] = 1;
        if(s[l] == '0') sum[rt].c[1][2] = 0, sum[rt].c[1][1] = 1;
        if(s[l] == '1') sum[rt].c[2][3] = 0, sum[rt].c[2][2] = 1;
        if(s[l] == '7') sum[rt].c[3][4] = 0, sum[rt].c[3][3] = 1;
        if(s[l] == '6') sum[rt].c[3][3] = 1, sum[rt].c[4][4] = 1;
        return;
    }

    int mid = l + r >> 1;
    build(l, mid, rt << 1);
    build(mid + 1, r, rt << 1 | 1);
    sum[rt] = add(sum[rt << 1], sum[rt << 1 | 1]);
}

node query(int ql, int qr, int l, int r, int rt) {
    if(ql <= l && qr >= r) return sum[rt];

    int mid = l + r >> 1;
    if(qr <= mid) return query(ql, qr, l, mid, rt << 1);
    if(ql > mid) return query(ql, qr, mid + 1, r, rt << 1 | 1);
    return add(query(ql, qr, l, mid, rt << 1), query(ql, qr, mid + 1, r, rt << 1 | 1));
}

int main() {
    scanf("%d%d", &n, &m);
    scanf("%s", s + 1);
    build(1, n, 1);

    for(int i = 1; i <= m; i++) {
        int l, r; scanf("%d%d", &l, &r);
        node res = query(l, r, 1, n, 1);
        if(res.c[0][4] >= MAXN) puts("-1");
        else printf("%d
", res.c[0][4]);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/lwqq3/p/11537649.html