• Codeforces Good Bye 2016 E. New Year and Old Subsequence


    传送门

    题意:
    给出一个长度为(n)的串,现在有(q)个询问,每个询问是一个区间([l,r]),要回答在区间([l,r])中,最少需要删多少个数,满足区间中包含(2017)的子序列而不包含(2016)的子序列。

    思路:

    • 先不考虑多个询问,那么这个问题区间(dp)可以解决,状态定义中要附加状态转移的代价。
    • 比如当前数字为(7),那么显然从状态(201)转移过来需要(0)的花费;但如果不要(7),那么从状态(201)到状态(201)则需要(1)的花费。
    • 同理,若数字为(6)时,若前面处于状态(201)或者(2017),显然此时的状态只能保持不能发生其它转移,但是保持也需要(1)的代价才行。
    • 以上我们定义的是将(0,1,2,3,4)分别表示状态(empty,2,20,201,2017),对于每个数的状态转移都有确定的代价,这好像叫有限状态自动机?
    • 考虑多个询问,因为每个询问是多个区间的问题,所以我们可以想到用线段树来保存区间信息,也就是说直接把(dp)挂树上去就行了。(区间(dp)支持区间合并)

    妙啊。

    #include <bits/stdc++.h>
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int N = 200005;
     
    int n, q;
    char s[N];
     
    struct node{
        int a[5][5];
        node() { memset(a, INF, sizeof(a)); }
        node operator + (const node &other) const {
            node 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] + other.a[k][j]);
                    }
                }
            }
            return res;
        }
    }tr[N << 2];
     
    void build(int o, int l, int r) {
        if(l == r) {
            tr[o] = node();
            for(int i = 0; i < 5; i++) tr[o].a[i][i] = 0;
            if(s[l] == '2') tr[o].a[0][1] = 0, tr[o].a[0][0] = 1;
            if(s[l] == '0') tr[o].a[1][2] = 0, tr[o].a[1][1] = 1;
            if(s[l] == '1') tr[o].a[2][3] = 0, tr[o].a[2][2] = 1;
            if(s[l] == '7') tr[o].a[3][4] = 0, tr[o].a[3][3] = 1;
            if(s[l] == '6') tr[o].a[3][3] = tr[o].a[4][4] = 1;
            return;
        }
        int mid = (l + r) >> 1;
        build(o << 1, l, mid); build(o << 1|1, mid + 1, r);
        tr[o] = tr[o << 1] + tr[o << 1|1];
    }
    node query(int o, int l, int r, int L, int R) {
        if(L <= l && r <= R) return tr[o];
        int mid = (l + r) >> 1;
        if(R <= mid) return query(o << 1, l, mid, L, R);
        if(L > mid) return query(o << 1|1, mid + 1, r, L, R);
        return query(o << 1, l, mid, L, R) + query(o << 1|1, mid + 1, r, L, R);
    }
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> n >> q;
        cin >> s + 1;
        build(1, 1, n);
        while(q--) {
            int l, r; cin >> l >> r;
            node ans = query(1, 1, n, l, r);
            cout << (ans.a[0][4] > n ? -1 : ans.a[0][4]) << '
    ';
        }
        return 0;
    }
    
  • 相关阅读:
    事件驱动模型 泽桐
    装饰器 泽桐
    多用户在线FTP程序 泽桐
    gevent协程、select IO多路复用、socketserver模块 改造多用户FTP程序例子 泽桐
    mysql系列学习 泽桐
    mysql练习题 泽桐
    第1章 Python基础 泽桐
    协程 泽桐
    利用统计进行中文分词与词性分析
    js 数字输入控制,保留两位小数
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11491321.html
Copyright © 2020-2023  润新知