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; }

浙公网安备 33010602011771号