CF750E New Year and Old Subsequence

题目链接:CF750E New Year and Old Subsequence

E. New Year and Old Subsequence

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 _a__i_ and ending at the index _b__i_ (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 s and 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 _a__i_ and _b__i_ (1 ≤ _a__i_ ≤ _b__i_ ≤ 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".


题意: 在区间\([l,r]\)中删去最少的字符数使得在这个区间内不含有子序列\("2016"\)且含有子序列\("2017"\),如果无法满足条件,输出\(-1\).

题解: 首先看到题目中要求区间的某个值,想到用某种数据结构来维护这个值.

然而这个最小值似乎是要用\(DP\)来求的?

那么这里就有点动态\(DP\)的意思了:我们将某个位置的状态加入矩阵中,再对这个序列开一棵线段树,线段树中的节点维护矩阵的状态.

我们将\("2017"\)拆成5份,分别是\(\empty,2,20,201,2017\),用\(0 \to 4\)表示这\(5\)个状态.

我们设转移矩阵\[D= \left[ \begin{matrix} a_{0,0} & ... & a_{0,4} \\ a_{i,j-1} & a_{i,j} & a_{i,j+1} \\ a_{4,0} & ... & a_{4,4} \end{matrix} \right] \tag{3} \]
其中\(a_{i,j}\)表示从\(i\)状态转移到\(j\)状态所需要的删去的字符数.

那么当我们枚举到一个位置的时候,假设这个位置是\(2\),那么如果不删去字符显然会形成状态\(1\),为了维持之前的状态\(0\),则需要删去这个字符,删去的字符数为1.那么对于某一位为\(2\),显然这位的转移矩阵为\[D= \left[ \begin{matrix} 1 & 0 & \inf & \inf & \inf \\ \inf & 0 & \inf & \inf & \inf \\ \inf & \inf & 0 & \inf & \inf \\ \inf & \inf & \inf & 0 & \inf \\ \inf & \inf & \inf & \inf & 0 \end{matrix} \right] \tag{3} \]

同理,对于该位为\(0,1,7\)都是一样的.

但是如果该位为\(6\)呢?显然我们是不能让串中出现\("2016"\)的,所以是一定要删除这个字符的,所以它的转移矩阵为\[D= \left[ \begin{matrix} 0 & \inf & \inf & \inf & \inf \\ \inf & 0 & \inf & \inf & \inf \\ \inf & \inf & 0 & \inf & \inf \\ \inf & \inf & \inf & 1 & \inf \\ \inf & \inf & \inf & \inf & 1 \end{matrix} \right] \tag{3} \]

也就是说,如果串中已经出现了\("201"\)或是\("2017"\),那么这个\(6\)就必须要删掉(或是其他位置删掉某个数字).

但是我们知道,矩阵乘法的运算法则是\(c_{i,j}=\sum_{k=1}^{n}a_{i,k}*b_{k,j}\),而我们这里是需要求一个最小值的,所以我们可以改一下矩阵的运算方法:\(c_{i,j}=max\{a_{i,k}+b_{k,j}\},k\in[1,n]\)

至于为什么这样是成立的,可以类比一下floyed求最短路更新的过程,因为这样的运算也是满足结合律的.

但是有点要注意,也就是矩阵乘法是不满足交换律的,也就是\(A*B\)不一定等于\(B*A\),而线段树的\(pushup\)一般是将左儿子的矩阵乘到右儿子的矩阵上,所以要注意一下哪个矩阵放在左边(虽然这题矩阵的构造方法是统一的,也就是说这题不用考虑这个问题)

看代码理解一下吧.

#include<bits/stdc++.h>
#define ll(x) (x << 1)
#define rr(x) (x << 1 | 1)
using namespace std;
const int N = 2e5+5;
const int inf = 0x3f3f3f3f;

int n, m;
char s[N];

struct Matrix{
    int a[5][5];
    Matrix(){ memset(a, 0x3f, sizeof(a)); }
    Matrix operator * (Matrix x){
        Matrix res;
        for(int i = 0; i < 5; i++)
            for(int j = 0; j < 5; j++)
                for(int k = 0; k < 5; k++)
                    res.a[i][j] = min(res.a[i][j], a[i][k]+x.a[k][j]);
        return res;
    }
};

struct SegmentTree{
    int l, r; Matrix M;
}t[N*4];

void up(int x){ t[x].M = t[ll(x)].M*t[rr(x)].M; }

void build(int x, int l, int r){
    t[x].l = l, t[x].r = r; int mid = (l+r>>1);
    if(l == r){
        for(int i = 0; i < 5; i++) t[x].M.a[i][i] = 0;
        if(s[l] == '2') t[x].M.a[0][0] = 1, t[x].M.a[0][1] = 0;
        if(s[l] == '0') t[x].M.a[1][1] = 1, t[x].M.a[1][2] = 0;
        if(s[l] == '1') t[x].M.a[2][2] = 1, t[x].M.a[2][3] = 0;
        if(s[l] == '7') t[x].M.a[3][3] = 1, t[x].M.a[3][4] = 0;
        if(s[l] == '6') t[x].M.a[3][3] = 1, t[x].M.a[4][4] = 1;
        return;
    }
    build(ll(x), l, mid), build(rr(x), mid+1, r); up(x);
}

Matrix query(int x, int l, int r){
    if(l <= t[x].l && t[x].r <= r) return t[x].M;
    int mid = (t[x].l+t[x].r>>1);
    if(r <= mid) return query(ll(x), l, r);
    if(mid < l) return query(rr(x), l, r);
    return query(ll(x), l, r)*query(rr(x), l, r);
}

int main(){
    ios::sync_with_stdio(false);
    int x, y; cin >> n >> m >> (s+1);
    build(1, 1, n);
    for(int i = 1; i <= m; i++){
        cin >> x >> y;
        Matrix ans = query(1, x, y);
        cout << (ans.a[0][4] > n ? -1 : ans.a[0][4]) << endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/BCOI/p/10329108.html