time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
A string t is called nice if a string "2017" occurs in t as a subsequence but a string "2016" doesn't occur in t as a subsequence. For example, strings "203434107" and "9220617" are nice, while strings "20016", "1234" and "20167" aren't nice.
The ugliness of a string is the minimum possible number of characters to remove, in order to obtain a nice string. If it's impossible to make a string nice by removing characters, its ugliness is - 1.
Limak has a string s of length n, with characters indexed 1 through n. He asks you q queries. In the i-th query you should compute and print the ugliness of a substring (continuous subsequence) of s starting at the index ai and ending at the index bi (inclusive).
Input
The first line of the input contains two integers n and q (4 ≤ n ≤ 200 000, 1 ≤ q ≤ 200 000) — the length of the string sand the number of queries respectively.
The second line contains a string s of length n. Every character is one of digits '0'–'9'.
The i-th of next q lines contains two integers ai and bi (1 ≤ ai ≤ bi ≤ n), describing a substring in the i-th query.
Output
For each query print the ugliness of the given substring.
Examples
input
Copy
8 3
20166766
1 8
1 7
2 8
output
Copy
4
3
-1
input
Copy
15 5
012016662091670
3 4
1 14
4 15
1 13
10 15
output
Copy
-1
2
1
-1
-1
input
Copy
4 2
1234
2 4
1 2
output
Copy
-1
-1
Note
In the first sample:
- In the first query, ugliness("20166766") = 4 because all four sixes must be removed.
- In the second query, ugliness("2016676") = 3 because all three sixes must be removed.
- In the third query, ugliness("0166766") = - 1 because it's impossible to remove some digits to get a nice string.
In the second sample:
- In the second query, ugliness("01201666209167") = 2. It's optimal to remove the first digit '2' and the last digit '6', what gives a string "010166620917", which is nice.
- In the third query, ugliness("016662091670") = 1. It's optimal to remove the last digit '6', what gives a nice string "01666209170".
题意给出长度为n的串S, 以及m次询问, 每次询问给出l, r。 求在中最少删除多少个字符满足
这段序列, 只含有2017, 不含有2016
设为第i个位置匹配到"?2017"(?指除2, 0, 1, 7, 6外的其他数字)的第j个字符需要的最小代价
对于, 从
转移,
若 若当前字符添加, 会导致状态转移到j + 1, 保持状态需要删除当前字符, 代价为1, 否则代价为0。
若, 且当前添加当前字符到不了当前状态, 则代价为INF, 否则代价0
若, 从后面的状态转回去, 显然代价为INF
可以使用矩阵转移, 将原本的乘法操作, 改为加法, 累加改成取min
下面表示的矩阵中用x = INF
当前字符为'2'时
当前字符为'0'时
当前字符为'1'时
当前字符为'7'时
当前字符为'6'时
初始矩阵为
我们只需要把转移矩阵相乘得到A, 再将初始矩阵乘以A即是答案
从状态1转到5, 因为取min, 所以答案即是
如何得到A? 使用线段树, 每个节点存一个矩阵。 查询时候区间查询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 == '7')
res.m[4][4] = 1, res.m[4][5] = 0;
if (s == '6')
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);
build(1, 1, n);
while (m--)
{
int ql, qr;
scanf("%d%d", &ql, &qr);
M ans = query(1, 1, n, ql, qr);
printf("%d\n", ans.m[1][5] == INF ? -1 : ans.m[1][5]);
}
return TIME;
}