【Codeforces 1149 B】Three Religions

题意:给一个字符串\(s\),现在有三个空串\(a、b、c\)

\(q\)个操作,每一个是

①给\(a、b、c\)中的一个末尾添加一个字符。

②把\(a、b、c\)中的一个末尾字符去掉。

每次操作后问是否可以将\(a、b、c\)分别作为\(s\)的一个不交叉的子序列。

思路:首先我们可以考虑\(dp\)

\(dp(l_a,l_b,l_c)\)表示现在\(a\)串匹配了\(l_a\)个,\(b\)串匹配了\(l_b\)个,\(c\)串匹配了\(l_c\)个,最小匹配到\(s\)串的第几位。

那么转移的时候枚举现在将要添加\(a、b、c\)串中哪一个的一个字符,

转移到\(dp(l_a+1,l_b,l_c)\)还是\(dp(l_a,l_b+1,l_c)\)还是\(dp(l_a,l_b,l_c+1)\)

那么就发现我们要预处理出第\(i\)位后面第一个\(c\)字符在哪里,记为\(nxt(i,c)\)

这样就可以\(O(1)\)转移了。状态数为\(O(len_a\times len_b\times len_c)\)

但这样每一次操作后都要重算,十分浪费。

我们打个表观察一下每次操作后\(dp\)数组会有什么变化。

然后就可以发现:

①操作后只会添加\(l_i=len_i\)的所有状态,其中\(i\)为此次操作中修改的串。

②操作后不会改变任何\(dp\)值。

这样就好了。

因为有三个串,写起来十分不方便。

我转移的时候还把\(a[l_a+1]\)写了个\(a.back()\)上去。。。

猜你喜欢

转载自www.cnblogs.com/denverjin/p/10802620.html