题目链接:https://vjudge.net/problem/CodeForces-750E
题解:哇,原来这个也四个原题。。。。。。维护矩阵的还真是第一次做,这里就说一下CF那题的思路吧
因为最后要2017,那么我们分为5个子序列 空 2 20 201 2017 每一个都代表一个状态,并且维护一下得到他们最少删除字符的数量,因此我们加上某个字符,相应的数量就会发生变化,我们用矩阵来表示这种数量的变化,比如:mat[i][j]就表示前一个状态是i 得到后一个状态j 最少删除字符的数量,初始状态下mat[i][i]就是0了,要注意的是,加上6的时候,对应前面出现201的就要删去6了,即mat[3][3] = mat[4][4] = 1,那么此时的矩阵合并就是像floyd那样
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
const int N = 2e5 + 10;
struct MAT {
int mat[5][5];
void init() {
memset(mat, INF, sizeof(mat));
}
};
struct node {
int l, r;
MAT m;
}tree[N << 2];
int n, q;
char s[N];
MAT cul(MAT x, MAT y) {
MAT z;
for(int i = 0; i < 5; i++)
for(int j = 0; j < 5; j++) {
z.mat[i][j] = INF;
for(int k = 0; k < 5; k++)
z.mat[i][j] = min(z.mat[i][j], x.mat[i][k] + y.mat[k][j]);
}
return z;
}
void build(int l, int r, int cur) {
tree[cur].l = l;
tree[cur].r = r;
tree[cur].m.init();
if(l == r) {
for(int i = 0; i < 5; i++) tree[cur].m.mat[i][i] = 0;
if(s[l] == '2') tree[cur].m.mat[0][0] = 1, tree[cur].m.mat[0][1] = 0;
if(s[l] == '0') tree[cur].m.mat[1][1] = 1, tree[cur].m.mat[1][2] = 0;
if(s[l] == '1') tree[cur].m.mat[2][2] = 1, tree[cur].m.mat[2][3] = 0;
if(s[l] == '7') tree[cur].m.mat[3][3] = 1, tree[cur].m.mat[3][4] = 0;
if(s[l] == '6') tree[cur].m.mat[3][3] = 1, tree[cur].m.mat[4][4] = 1;
return;
}
int mid = (l + r) >> 1;
build(l, mid, cur << 1);
build(mid + 1, r, cur << 1 | 1);
tree[cur].m = cul(tree[cur << 1].m, tree[cur << 1 | 1].m);
}
MAT query(int pl, int pr, int cur) {
if(pl <= tree[cur].l && tree[cur].r <= pr) return tree[cur].m;
MAT z;
z.init();
for(int i = 0; i < 5; i++) z.mat[i][i] = 0;
if(pl <= tree[cur << 1].r) z = cul(z, query(pl, pr, cur << 1));
if(pr >= tree[cur << 1 | 1].l) z = cul(z, query(pl, pr, cur << 1 | 1));
return z;
}
int main() {
scanf("%d %d", &n, &q);
scanf("%s", s + 1);
build(1, n, 1);
int l, r, ans;
while(q--) {
scanf("%d %d", &l, &r);
ans = query(l, r, 1).mat[0][4];
if(ans > n) ans = -1;
printf("%d\n", ans);
}
return 0;
}