codeforces 750E and 南昌网络赛的类类似 (线段树+矩阵转移dp)

题目链接:http://codeforces.com/problemset/problem/750/e

题意: 单组第一行n,q两个整数,表示给你一个长度为n的串q次查询

第二行字符串s,表示长度为n的字符串s;

后面q行 每行两个整数l,r表示要你输出字符串在[l,r]区间内最少删除几个字符使[l,r]中有2017没有2016,如果不可能则为-1;

 

这题巧妙的利用了矩阵来转移dp方程,

dp的状态是指

如: ?表示没有(2,0,1,7,6)

         1                   2     3  4   5

原字符串为?2时当添加字符0在后面

要使字符串只有2没有20的状态为 状态dp[2][2] +1 表示要删除0这个字符才行

而要又20字符的话 dp[2][3] +0就不需要删除字符

这个dp记录着状态转变所需要删除的字符数

就以这个思路去想

最后给代码,懒得讲了还有太多东西没学就先说到这:

#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <algorithm>
#define lc d<<1
#define rc d<<1|1
#define mid ((l+r)>>1)
using namespace std;
const int mx = 2e5+5;
const int inf = 0x3f3f3f3f;
char s[mx];

struct mat {
    int dp[7][7];
    mat() {
        memset(dp, 0x3f3f3f3f, sizeof(dp));
        for (int i = 1; i <= 5; ++i) dp[i][i] = 0;
    }
    mat operator*(const mat &t) const {
        mat a;
        for (int i = 1; i <= 5; ++i) a.dp[i][i] = inf;
        for (int k = 1; k <= 5; ++k)
            for (int i = 1; i <= 5; ++i)
                for (int j = 1; j <= 5; ++j)
                    a.dp[i][j] = min(a.dp[i][j], dp[i][k]+t.dp[k][j]);
        return a;
    }
}ma[6];

struct tree {
    mat a;
}T[mx*4];

mat get(char ch) {
    mat a;
    if (ch == '2')
        a.dp[1][1] = 1, a.dp[1][2] = 0;
    if (ch == '0')
        a.dp[2][2] = 1, a.dp[2][3] = 0;
    if (ch == '1')
        a.dp[3][3] = 1, a.dp[3][4] = 0;
    if (ch == '7')
        a.dp[4][4] = 1, a.dp[4][5] = 0;
    if (ch == '6')
        a.dp[5][5] = 1, a.dp[4][4] = 1;
    return a;

}

void pushup(int d) {
    T[d].a = T[lc].a*T[rc].a;
}

void build(int l, int r, int d) {
    if (l == r) {
        T[d].a = get(s[l]);
        return;
    }
    build(l, mid, lc);
    build(mid+1, r, rc);
    pushup(d);
    return;
}

mat Query(int l, int r, int L, int R, int d) {
    if (l == L && r == R) return T[d].a;
    if (R <= mid) return Query(l, mid, L, R, lc);
    if (mid < L) return Query(mid+1, r, L, R, rc);
    return Query(l, mid, L, mid, lc)*Query(mid+1, r, mid+1, R, rc);
}

int main () {
    int n, m;
    scanf("%d%d", &n, &m);
    scanf("%s", s+1);
    build(1, n, 1);
    for (int i = 0; i < m; ++i) {
        mat a;
        int l, r;
        scanf("%d%d", &l, &r);
        a = a*Query(1, n, l, r, 1);
        if (a.dp[1][5] == inf) puts("-1");
        else printf("%d\n", a.dp[1][5]);
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值