题意:长为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; }