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 rt) {
    if(ql <= l && qr >= r) return sum[rt];

    int mid = l + r >> 1;
    if(qr <= mid) return query(ql,qr,l,rt << 1);
    if(ql > mid) return query(ql,mid + 1,rt << 1 | 1);
    return add(query(ql,rt << 1),query(ql,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,1,1);
        if(res.c[0][4] >= MAXN) puts("-1");
        else printf("%d\n",res.c[0][4]);
    }
    return 0;
}
View Code

相关文章

自1998年我国取消了福利分房的政策后,房地产市场迅速开展蓬...
文章目录获取数据查看数据结构获取数据下载数据可以直接通过...
网上商城系统MySql数据库设计
26个来源的气象数据获取代码
在进入21世纪以来,中国电信业告别了20世纪最后阶段的高速发...