• 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 o 4)表示这(5)个状态.

    我们设转移矩阵$$D=
    left[
    egin{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}
    ight] ag{3}

    [其中$a_{i,j}$表示从$i$状态转移到$j$状态所需要的删去的字符数. 那么当我们枚举到一个位置的时候,假设这个位置是$2$,那么如果不删去字符显然会形成状态$1$,为了维持之前的状态$0$,则需要删去这个字符,删去的字符数为1.那么对于某一位为$2$,显然这位的转移矩阵为$$D= left[ egin{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} ight] ag{3} ]

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

    但是如果该位为(6)呢?显然我们是不能让串中出现("2016")的,所以是一定要删除这个字符的,所以它的转移矩阵为$$D=
    left[
    egin{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}
    ight] ag{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}},kin[1,n]$ 至于为什么这样是成立的,可以类比一下floyed求最短路更新的过程,因为这样的运算也是满足结合律的. 但是有点要注意,也就是矩阵乘法是不满足交换律的,也就是$A*B$不一定等于$B*A$,而线段树的$pushup$一般是将左儿子的矩阵乘到右儿子的矩阵上,所以要注意一下哪个矩阵放在左边(虽然这题矩阵的构造方法是统一的,也就是说这题不用考虑这个问题) 看代码理解一下吧. ```cpp #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; } ```]

  • 相关阅读:
    2015,刺激、快乐与煎熬
    Spring Security安全框架入门篇
    亲密接触Redis-第一天
    Shiro安全框架入门篇(登录验证实例详解与源码)
    javaweb异常提示信息统一处理(使用springmvc,附源码)
    ActiveMQ + NodeJS + Stomp 极简入门
    Java异常封装(自己定义错误码和描述,附源码)
    SpringMVC+BUI实现文件上传(附详解,源码下载)
    获取web项目中的webroot目录路径
    struts中request传递中文乱码问题
  • 原文地址:https://www.cnblogs.com/BCOI/p/10329108.html
Copyright © 2020-2023  润新知