题意:长为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; }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。