2019ICPC南昌网络赛C Hello 2019

题意:给出一个字符串,每次询问一个区间[l,r],求使得这个区间含有9102但不含有8102最少要删掉几个字符

首先我们考虑将串反转,这样就变成了含有2019但不含有2018的问题了

我们构建一个状态数为5的自动机

状态0:字符集为空

状态1:字符集为2

状态2:字符集为20

状态3:字符集为201

状态4:字符集为2019

每加入一个字符就为对应的两个状态连一条边

两个字串合并我们只需对两个字符串的自动机进行一次dp即可

这样我们维护一个自动机的线段树,每个区间维护一个子串的自动机

查询的时候合并字串区间的自动机即可

AC代码:

#include 
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=2e5+5;
struct Matrix {
    int a[5][5];

    void init() {
        memset(a, INF, sizeof(a));
        for (int i = 0; i < 5; i++)a[i][i] = 0;
    }
    void print()
    {
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++)cout << a[i][j] << " ";
            cout << endl;
        }
    }
    Matrix operator*(Matrix A) {
        Matrix ret;
        memset(ret.a,INF, sizeof(ret.a));
        for (int i = 0; i < 5; i++)
            for (int j = 0; j < 5; j++)
                for (int k = 0; k < 5; k++)
                    //因为是倒过来的2019,合并自动机我们要反过来合并
                    ret.a[i][j] = min(ret.a[i][j], A.a[i][k] + a[k][j]);
        return ret;
    }
}tree[maxn<<2];

char s[maxn];
void pushup(int rt) {
    tree[rt] = tree[rt << 1] * tree[rt << 1 | 1];
}
void build(int l,int r,int rt) {
    if (l == r) {
        tree[rt].init();
        if (s[l] == '2')tree[rt].a[0][0] = 1, tree[rt].a[0][1] = 0;
        else if (s[l] == '0')tree[rt].a[1][1] = 1, tree[rt].a[1][2] = 0;
        else if (s[l] == '1')tree[rt].a[2][2] = 1, tree[rt].a[2][3] = 0;
        else if (s[l] == '9')tree[rt].a[3][3] = 1, tree[rt].a[3][4] = 0;
        else if (s[l] == '8')tree[rt].a[3][3] = 1, tree[rt].a[4][4] = 1;
        return;
    }
    int m = (l + r) >> 1;
    build(l, m, rt << 1);
    build(m + 1, r, rt << 1 | 1);
    pushup(rt);
}

Matrix query(int L,int R,int l,int r,int rt) {
    if (L <= l && r <= R)return tree[rt];
    int m = (l + r) >> 1;
    Matrix res;
    res.init();
    if (L <= m)res = query(L, R, l, m, rt << 1);
    if (R > m)res = res * query(L, R, m + 1, r, rt << 1 | 1);
    return res;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n, q, l, r;
    cin >> n >> q;
    cin >> (s + 1);
    build(1, n, 1);
    while (q--) {
        cin >> l >> r;
        Matrix res = query(l, r, 1, n, 1);
        cout << (res.a[0][4] == INF ? -1 : res.a[0][4]) << '\n';
    }
    return 0;
}

 

你可能感兴趣的:(2019ICPC南昌网络赛C Hello 2019)