题目链接:http://codeforces.com/problemset/problem/750/e
题意: 单组第一行n,q两个整数,表示给你一个长度为n的串q次查询
第二行字符串s,表示长度为n的字符串s;
后面q行 每行两个整数l,r表示要你输出字符串在[l,r]区间内最少删除几个字符使[l,r]中有2017没有2016,如果不可能则为-1;
这题巧妙的利用了矩阵来转移dp方程,
dp的状态是指
如: ?表示没有(2,0,1,7,6)
1 2 3 4 5
原字符串为?2时当添加字符0在后面
要使字符串只有2没有20的状态为 状态dp[2][2] +1 表示要删除0这个字符才行
而要又20字符的话 dp[2][3] +0就不需要删除字符
这个dp记录着状态转变所需要删除的字符数
就以这个思路去想
最后给代码,懒得讲了还有太多东西没学就先说到这:
#include
#include
#include
#include
#include
#define lc d<<1
#define rc d<<1|1
#define mid ((l+r)>>1)
using namespace std;
const int mx = 2e5+5;
const int inf = 0x3f3f3f3f;
char s[mx];
struct mat {
int dp[7][7];
mat() {
memset(dp, 0x3f3f3f3f, sizeof(dp));
for (int i = 1; i <= 5; ++i) dp[i][i] = 0;
}
mat operator*(const mat &t) const {
mat a;
for (int i = 1; i <= 5; ++i) a.dp[i][i] = inf;
for (int k = 1; k <= 5; ++k)
for (int i = 1; i <= 5; ++i)
for (int j = 1; j <= 5; ++j)
a.dp[i][j] = min(a.dp[i][j], dp[i][k]+t.dp[k][j]);
return a;
}
}ma[6];
struct tree {
mat a;
}T[mx*4];
mat get(char ch) {
mat a;
if (ch == '2')
a.dp[1][1] = 1, a.dp[1][2] = 0;
if (ch == '0')
a.dp[2][2] = 1, a.dp[2][3] = 0;
if (ch == '1')
a.dp[3][3] = 1, a.dp[3][4] = 0;
if (ch == '7')
a.dp[4][4] = 1, a.dp[4][5] = 0;
if (ch == '6')
a.dp[5][5] = 1, a.dp[4][4] = 1;
return a;
}
void pushup(int d) {
T[d].a = T[lc].a*T[rc].a;
}
void build(int l, int r, int d) {
if (l == r) {
T[d].a = get(s[l]);
return;
}
build(l, mid, lc);
build(mid+1, r, rc);
pushup(d);
return;
}
mat Query(int l, int r, int L, int R, int d) {
if (l == L && r == R) return T[d].a;
if (R <= mid) return Query(l, mid, L, R, lc);
if (mid < L) return Query(mid+1, r, L, R, rc);
return Query(l, mid, L, mid, lc)*Query(mid+1, r, mid+1, R, rc);
}
int main () {
int n, m;
scanf("%d%d", &n, &m);
scanf("%s", s+1);
build(1, n, 1);
for (int i = 0; i < m; ++i) {
mat a;
int l, r;
scanf("%d%d", &l, &r);
a = a*Query(1, n, l, r, 1);
if (a.dp[1][5] == inf) puts("-1");
else printf("%d\n", a.dp[1][5]);
}
}