A digital string is "good": when it contains a subsequence 91029102 and does not contain a subsequence 81028102.
The bad value of a string is defined as how many characters are to remove at least, so that the string satisfies the "good" property. Output -1
if the string cannot satisfy the "good" property by removing some characters (0 or maybe more).
Input
The first line contains two integers n, Qn,Q(1\leq n,Q\leq2*10^5)(1≤n,Q≤2∗105). Where nn is the length of the string and QQ is the number of queries.
The second line contains a string ss that consists entirely of decimal numbers.
The next QQ line, each line contains two integers l, rl,r(1\leq l\leq r\leq n)(1≤l≤r≤n), denoting a query.
Output
For each query, output an answer which is the bad value of the substring s_ls_{l+1} \cdots s_rslsl+1⋯sr from ss.
样例输入复制
8 3
88988102
1 8
2 8
1 7
样例输出复制
4
3
-1
题意给出长度为n的串S, 以及m次询问, 每次询问给出l, r。 求在中最少删除多少个字符满足
这段序列, 只含有9102, 不含有8102
这题跟CF New Year and Old Subsequence 这题一样, 除了所给字符串不同的字符一个在尾, 一个在头
对于第一个字符不同, 状态可能很多。。 弱鸡不会, 还是反过来按最后一个字符不同来处理。
问题转化成求一个区间内只含有2019, 不含有2018, 最少删除多少个字符。
思路:
设为第i个位置匹配到"?2019"(?指除2, 0, 1, 9, 8外的其他数字)的第j个字符需要的最小代价
对于, 从
转移,
若 若当前字符添加, 会导致状态转移到j + 1, 保持状态需要删除当前字符, 代价为1, 否则代价为0。
若, 且当前添加当前字符到不了当前状态, 则代价为INF, 否则代价0
若, 从后面的状态转回去, 显然代价为INF
可以使用矩阵转移, 将原本的乘法操作, 改为加法, 累加改成取min
下面表示的矩阵中用x = INF
当前字符为'2'时
当前字符为'0'时
当前字符为'1'时
当前字符为'9'时
当前字符为'8'时
初始矩阵为
我们只需要把转移矩阵相乘得到A, 再将初始矩阵乘以A即是答案
从状态1转到5, 因为取min, 所以答案即是
如何得到A? 使用线段树, 每个节点存一个矩阵。 查询时候区间查询l, r即可(别忘了, l, r也要反一下)
代码:
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#ifdef LOCAL
#define debug(x) cout << "[" __FUNCTION__ ": " #x " = " << (x) << "]\n"
#define TIME cout << "RuningTime: " << clock() << "ms\n", 0
#else
#define TIME 0
#endif
#define hash_ 1000000009
#define Continue(x) { x; continue; }
#define Break(x) { x; break; }
const int mod = 998244353;
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
ll fpow(ll a, ll b, int mod) { ll res = 1; for (; b > 0; b >>= 1) { if (b & 1) res = res * a % mod; a = a * a % mod; } return res; }
char s[N];
struct M
{
int m[6][6];
M()
{
memset(m, 0x3f, sizeof m);
for (int i = 1; i <= 5; i++)
m[i][i] = 0;
}
}c[N << 2];
M add(M a, M b)
{
M ans;
for (int i = 1; i <= 5; i++)
for (int j = 1; j <= 5; j++)
{
ans.m[i][j] = INF;
for (int k = 1; k <= 5; k++)
ans.m[i][j] = min(ans.m[i][j], a.m[i][k] + b.m[k][j]);
}
return ans;
}
M get_M(char s)
{
M res;
if (s == '2')
res.m[1][1] = 1, res.m[1][2] = 0;
if (s == '0')
res.m[2][2] = 1, res.m[2][3] = 0;
if (s == '1')
res.m[3][3] = 1, res.m[3][4] = 0;
if (s == '9')
res.m[4][4] = 1, res.m[4][5] = 0;
if (s == '8')
res.m[5][5] = 1, res.m[4][4] = 1;
return res;
}
#define ls ((x) << 1)
#define rs ((x) << 1 | 1)
#define mid ((L) + (R) >> 1)
void push_up(int x)
{
c[x] = add(c[ls], c[rs]);
}
void build(int x, int L, int R)
{
if (L == R)
{
c[x] = get_M(s[L]);
return;
}
build(ls, L, mid);
build(rs, mid + 1, R);
push_up(x);
}
M query(int x, int L, int R, int ql, int qr)
{
if (ql <= L && qr >= R)
return c[x];
M u, v;
if (ql <= mid)
u = query(ls, L, mid, ql, qr);
if (qr > mid)
v = query(rs, mid + 1, R, ql, qr);
return add(u, v);
}
int main()
{
#ifdef LOCAL
freopen("D:/input.txt", "r", stdin);
#endif
int n, m;
cin >> n >> m;
scanf("%s", s + 1);
reverse(s + 1, s + n + 1);
build(1, 1, n);
while (m--)
{
int ql, qr;
scanf("%d%d", &ql, &qr);
int u = ql;
ql = n - qr + 1;
qr = n - u + 1;
M ans = query(1, 1, n, ql, qr);
printf("%d\n", ans.m[1][5] == INF ? -1 : ans.m[1][5]);
}
return TIME;
}