我是靠谱客的博主 热情水壶,这篇文章主要介绍CF1609 E. William The ObliviousCF1609 E. William The Oblivious,现在分享给大家,希望可以做个参考。

CF1609 E. William The Oblivious

题意

给定一个长度为 n n n的字符串 s s s,字符串内只含有 a , b , c a,b,c a,b,c三种字符,即 ∀ i , s [ i ] forall i,s[i] i,s[i] a , b , c a,b,c a,b,c中一个。
q q q次询问,每次询问会将 s [ p o s ] s[pos] s[pos]修改成 v v v,即 s [ p o s ] = v s[pos]=v s[pos]=v

你可以进行一种操作,使得任意一个位置的 s [ i ] s[i] s[i]转变成 a , b , c a,b,c a,b,c中的一个字符。

对于每次询问,需要回答:将当前字符串修改成子序列中不含abc的最小操作次数。

思路

线段树维护每一个连续子区间的信息,定义状态为:

  • d p [ r o o t ] [ 0 ] dp[root][0] dp[root][0]:将当前子串修改成子序列中不含a的最小操作次数。
  • d p [ r o o t ] [ 1 ] dp[root][1] dp[root][1]:将当前子串修改成子序列中不含b的最小操作次数。
  • d p [ r o o t ] [ 2 ] dp[root][2] dp[root][2]:将当前子串修改成子序列中不含c的最小操作次数。
  • d p [ r o o t ] [ 3 ] dp[root][3] dp[root][3]:将当前子串修改成子序列中不含ab的最小操作次数。
  • d p [ r o o t ] [ 4 ] dp[root][4] dp[root][4]:将当前子串修改成子序列中不含bc的最小操作次数。
  • d p [ r o o t ] [ 5 ] dp[root][5] dp[root][5]:将当前子串修改成子序列中不含abc的最小操作次数。

则状态转移为:

复制代码
1
2
3
4
5
6
7
8
root.dp[0] = left.dp[0] + right.dp[0]; root.dp[1] = left.dp[1] + right.dp[1]; root.dp[2] = left.dp[2] + right.dp[2]; root.dp[3] = min(left.dp[3] + right.dp[1], left.dp[0] + right.dp[3]); root.dp[4] = min(left.dp[1] + right.dp[4], left.dp[4] + right.dp[2]); root.dp[5] = min(left.dp[0] + right.dp[5], min(left.dp[5] + right.dp[2], left.dp[3] + right.dp[4]));

代码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; const int inf = 0x3f3f3f3f; int n, q; char s[N]; struct Tree { int l, r; int dp[6]; } tr[N * 4]; void pushup(int p) { auto &root = tr[p], &left = tr[p << 1], &right = tr[p << 1 | 1]; root.dp[0] = left.dp[0] + right.dp[0]; root.dp[1] = left.dp[1] + right.dp[1]; root.dp[2] = left.dp[2] + right.dp[2]; root.dp[3] = min(left.dp[3] + right.dp[1], left.dp[0] + right.dp[3]); root.dp[4] = min(left.dp[1] + right.dp[4], left.dp[4] + right.dp[2]); root.dp[5] = min(left.dp[0] + right.dp[5], min(left.dp[5] + right.dp[2], left.dp[3] + right.dp[4])); } void build(int p, int l, int r) { tr[p] = {l, r}; if (l == r) { memset(tr[p].dp, 0, sizeof tr[p].dp); tr[p].dp[s[l] - 'a'] = 1; return; } int mid = (tr[p].l + tr[p].r) >> 1; build(p << 1, l, mid); build(p << 1 | 1, mid + 1, r); pushup(p); } void modify(int p, int x, char v) { if (tr[p].l == tr[p].r && tr[p].l == x) { s[x] = v; memset(tr[p].dp, 0, sizeof tr[p].dp); tr[p].dp[s[x] - 'a'] = 1; return; } int mid = (tr[p].l + tr[p].r) >> 1; if (x <= mid) modify(p << 1, x, v); else modify(p << 1 | 1, x, v); pushup(p); } int main() { cin >> n >> q; cin >> s + 1; build(1, 1, n); while (q--) { int x, res = inf; char val; cin >> x >> val; modify(1, x, val); cout << tr[1].dp[5] << "n"; } return 0; }

最后

以上就是热情水壶最近收集整理的关于CF1609 E. William The ObliviousCF1609 E. William The Oblivious的全部内容,更多相关CF1609内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(95)

评论列表共有 0 条评论

立即
投稿
返回
顶部