CF750E New Year and Old Subsequence 解题报告

Description

给定一个数字串,每次询问给出一个区间 $l,r$,求这个区间至少要删去几个字符满足存在子序列 $2017$ 而不存在子序列 $2016$。若无解,输出 $-1$。

Solution

DDP 好题。

考虑朴素的动态规划。$dp[i][0/1/2/3/4]$ 表示**恰好**包含 $空集合/2/20/201/2017 最少删去字符数。得到

- $dp_{i,0} = dp_{i-1,0} + [s_i == 2]$
- $dp_{i,1} = min(dp_{i-1,1} + [s_i == 0], dp_{i-1,0}[s_i == 2])$
- $dp_{i,2} = min(dp_{i-1,2} + [s_i == 1], dp_{i-1,1}[s_i == 0])$
- $dp_{i,3} = min(dp_{i-1,3} + [s_i == 6~or~s_i == 7], dp_{i-1,2}[s_i == 1])$
- $dp_{i,4} = min(dp_{i-1,4} + [s_i == 6], dp_{i-1,3}[s_i == 7])$

就是 DDP 板子了。每次询问时可以将每次的矩乘优化成 $O(n^2)$。具体实现看代码。

Code

#include<bits/stdc++.h>
using namespace std;
inline int read() {
    int x = 0, f = 1; char c = getchar();
    while (c < '0' || c > '9') {if (c == '-') f = -f; c = getchar();}
    while (c >= '0' && c <= '9') {x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}
    return x * f;
}
const int N = 2e5 + 10, S = 5;
int n, q;
struct matrix {
    int a[S][S];
    matrix friend operator * (matrix x, matrix y) {
        matrix t; memset(t.a, 0x3f, sizeof t.a);
        for (int i = 0; i < S; ++ i)
            for (int j = 0; j < S; ++ j)
                for (int k = 0; k < S; ++ k)
                    t.a[i][j] = min(t.a[i][j], x.a[i][k] + y.a[k][j]);
        return t;
    }
    matrix friend operator / (matrix x, matrix y) {
        matrix t; memset(t.a, 0x3f, sizeof t.a);
        for (int i = 0; i < S; ++ i)
            for (int j = 0; j < S; ++ j)
                t.a[0][i] = min(t.a[0][i], x.a[0][j] + y.a[j][i]);
        return t;
    }
}g[N], ans, fir;
struct SegmentTree {
    matrix v[N<<2];
    #define ls p << 1
    #define rs p << 1 | 1
    inline void build(int p, int l, int r) {
        if (l == r) return v[p] = g[l], void();
        int mid = l + r >> 1;
        build(ls, l, mid); build(rs, mid + 1, r);
        v[p] = v[ls] * v[rs];
    }
    inline void query(int p, int l, int r, int L, int R) {
        if (L <= l && r <= R) return ans = ans / v[p], void();
        int mid = l + r >> 1;
        if (L <= mid) query(ls, l, mid, L, R);
        if (R > mid) query(rs, mid + 1, r, L, R);
    }
}tr; 
int main () {
    n = read(); q = read();
    memset(fir.a, 0x3f, sizeof fir.a); fir.a[0][0] = 0;
    for (int i = 1; i <= n; ++ i) {
        char ch; scanf(" %c", &ch);
        memset(g[i].a, 0x3f, sizeof g[i].a);
        for (int j = 0; j < S; ++ j) g[i].a[j][j] = 0;
        if (ch == '2')  g[i].a[0][0] = 1, g[i].a[0][1] = 0; 
        if (ch == '0')     g[i].a[1][1] = 1, g[i].a[1][2] = 0;
        if (ch == '1')  g[i].a[2][2] = 1, g[i].a[2][3] = 0;
        if (ch == '6')    g[i].a[3][3] = 1, g[i].a[4][4] = 1;
        if (ch == '7')     g[i].a[3][3] = 1, g[i].a[3][4] = 0;
    }
    tr.build(1, 1, n);
    while (q --) {
        int l = read(), r = read(); ans = fir;
        tr.query(1, 1, n, l, r);
        printf("%d\n", ans.a[0][4] <= n ? ans.a[0][4] : -1);
    }
    return 0;
}
View Code

 

posted @ 2023-01-13 13:34  LikC1606  阅读(25)  评论(0)    收藏  举报