题目传送门

题解:

id[ i ][ j ] 代表的是在第j个位置之后的第i个字符的位置在哪里。

dp[ i ][ j ][ k ] 代表的是 第一个串匹配到第i个位置, 第二个串匹配到第j个位置, 第三个串匹配到第k个位置之后,最后面一个字符的位置在哪里。

如果题目只询问一次,那么应该很容易想到n^3的写法。

for(int i = ; i <= n1; ++i){
for(int j = ; j <= n2; ++j){
for(int k = ; k <= n3; ++k){
if(i+j+k) dp[i][j][k] = n + ;
if(i) dp[i][j][k] = min(dp[i][j][k], id[ss[][i]-'a'][dp[i-][j][k]]);
if(j) dp[i][j][k] = min(dp[i][j][k], id[ss[][j]-'a'][dp[i][j-][k]]);
if(k) dp[i][j][k] = min(dp[i][j][k], id[ss[][k]-'a'][dp[i][j][k-]]);
}
}

但是,在一共有q次询问的前提下,肯定是不能每次询问都直接n^3的暴力得到的。

现在假如我们知道了 dp[3][4][6]的信息。

现在在第3个串后面加了一个字符,也就是说我们需要知道dp[3][4][7]的信息。

可以观察2遍的 n^3中的结果。

其中 for  i  from 0 to 3

    for j  from 0 to 4

      for k from 0 to 6 的dp值和前面没有任何不同。

唯一区别的是 :

  for i from 0 to 3

    for j from 0 to 4

      for k from 7 to 7 的dp值会发生变化。

所以我们只需要跑一边

   for k from 7 to 7

    for i from 0 to 3

      for k from  0 to  4的dp值,更新这一块的dp值就好了。

如果 i + 1了 或者 j + 1了也是一样的道理。

所以每次更新所跑的值都是 len ^ 2。

最后的复杂度就是 q * len ^ 2. (len <= 250)。

代码:

#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const int _inf = 0xc0c0c0c0;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL _INF = 0xc0c0c0c0c0c0c0c0;
const LL mod = (int)1e9+;
const int N = 1e5 + ;
char s[N];
int id[][N];
int dp[][][];
char ss[][N];
void Ac(){
int n, m;
scanf("%d%d", &n, &m);
scanf("%s", s+);
for(int i = ; i < ; ++i)
id[i][n+] = n+;
for(int j = n; j >= ; --j){
for(int i = ; i < ; ++i){
id[i][j] = id[i][j+];
}
if(j < n) id[s[j+]-'a'][j] = j+;
}
int l1, l2, l3, n1, n2, n3;
l1 = l2 = l3 = n1 = n2 = n3 = ;
char op[];
int t;
for(int _ = ; _ <= m; ++_){
scanf("%s", op);
if(op[] == '+'){
scanf("%d%s", &t, op);
if(t == ) {
++n1; ss[][n1] = op[];
for(int i = n1; i <= n1; ++i){
for(int j = ; j <= l2; ++j){
for(int k = ; k <= l3; ++k){
if(i+j+k) dp[i][j][k] = n + ;
if(i) dp[i][j][k] = min(dp[i][j][k], id[ss[][i]-'a'][dp[i-][j][k]]);
if(j) dp[i][j][k] = min(dp[i][j][k], id[ss[][j]-'a'][dp[i][j-][k]]);
if(k) dp[i][j][k] = min(dp[i][j][k], id[ss[][k]-'a'][dp[i][j][k-]]);
}
}
}
}
if(t == ) {
++n2; ss[][n2] = op[];
for(int j = n2; j <= n2; ++j){
for(int i = ; i <= l1; ++i){
for(int k = ; k <= l3; ++k){
if(i+j+k) dp[i][j][k] = n + ;
if(i) dp[i][j][k] = min(dp[i][j][k], id[ss[][i]-'a'][dp[i-][j][k]]);
if(j) dp[i][j][k] = min(dp[i][j][k], id[ss[][j]-'a'][dp[i][j-][k]]);
if(k) dp[i][j][k] = min(dp[i][j][k], id[ss[][k]-'a'][dp[i][j][k-]]);
}
}
}
}
if(t == ) {
++n3; ss[][n3] = op[];
for(int k = n3; k <= n3; ++k){
for(int i = ; i <= l1; ++i){
for(int j = ; j <= l2; ++j){
if(i+j+k) dp[i][j][k] = n + ;
if(i) dp[i][j][k] = min(dp[i][j][k], id[ss[][i]-'a'][dp[i-][j][k]]);
if(j) dp[i][j][k] = min(dp[i][j][k], id[ss[][j]-'a'][dp[i][j-][k]]);
if(k) dp[i][j][k] = min(dp[i][j][k], id[ss[][k]-'a'][dp[i][j][k-]]);
}
}
}
}
}
else {
scanf("%d", &t);
if(t == ) --n1;
if(t == ) --n2;
if(t == ) --n3;
}
l1 = n1; l2 = n2; l3 = n3;
if(dp[l1][l2][l3] != n + ) puts("YES");
else puts("NO");
}
}
int main(){
Ac();
return ;
}
/*
6 8
abdabc
+ 1 a
+ 1 d
+ 2 b
+ 2 c
*/

CodeForces - 1150 D Three Religions的更多相关文章

  1. CF 1150 D Three Religions——序列自动机优化DP

    题目:http://codeforces.com/contest/1150/problem/D 老是想着枚举当前在给定字符串的哪个位置,以此来转移. 所以想对三个串分别建 trie 树,然后求出三个t ...

  2. Codeforces 1149 B - Three Religions

    B - Three Religions 思路:dp dp[i][j][k]:a的前i个和b的前j个和c的前k个能构成的最前面的位置 删字符时状态不用改变,加字符时只会改变1*250*250个状态 代码 ...

  3. Codeforces Round #556 (Div. 2) - D. Three Religions(动态规划)

    Problem  Codeforces Round #556 (Div. 2) - D. Three Religions Time Limit: 3000 mSec Problem Descripti ...

  4. Codeforces Round #556 (Div. 2) D. Three Religions 题解 动态规划

    题目链接:http://codeforces.com/contest/1150/problem/D 题目大意: 你有一个参考串 s 和三个装载字符串的容器 vec[0..2] ,然后还有 q 次操作, ...

  5. codeforces#1150D. Three Religions(dp+序列自动机)

    题目链接: https://codeforces.com/contest/1150/problem/D 题意: 给出长度为$n$的字符串,和$q$次询问 每次询问是,给$x$宗教增加一个字符$key$ ...

  6. Three Religions CodeForces - 1149B (字符串,dp)

    大意: 给定字符串S, 要求维护三个串, 支持在每个串末尾添加或删除字符, 询问S是否能找到三个不相交的子序列等于三个串. 暴力DP, 若不考虑动态维护的话, 可以直接$O(len^3)$处理出最少需 ...

  7. Codeforces 1050D Three Religions (dp+序列自动机)

    题意: 给一个1e5的串str,然后有三个起始空串,不超过1000次操作,对三个字符串的一个尾部加一个字符或者减一个字符,保证每个字符不会超过250 每次操作之后询问你这三个串是不是可以组成str的子 ...

  8. Codeforces Educational Codeforces Round 5 C. The Labyrinth 带权并查集

    C. The Labyrinth 题目连接: http://www.codeforces.com/contest/616/problem/C Description You are given a r ...

  9. Educational Codeforces Round 5

    616A - Comparing Two Long Integers    20171121 直接暴力莽就好了...没什么好说的 #include<stdlib.h> #include&l ...

随机推荐

  1. 游戏开发3D基础知识

    概念学习: 向量 向量简介 我们将所有彼此平行的向量进行平移,使其起点与坐标原点重合,当某一向量的起始端与坐标原点重合,我们成该向量处于标准位置.这样,我们就可用向量的终点坐标来描述一个处于标准位置的 ...

  2. c#小灶——输出语句

    前面我我们学习了如何在控制台输出一句话,今天我们学习一下更详细的输出方式. Console.WriteLine();和Console.Write(); 我们来看一下下面几行代码, using Syst ...

  3. python_0基础开始_day03

    第三节 一.整形和布尔值的转换 int整型 python3: 全部都是整型 python2: 整型,长整型long 十进制转换二进制 # 将十进制的168转换为二进制 ​#得出结果 将十进制的168转 ...

  4. Java学习多线程第二天

    内容介绍 线程安全 线程同步 死锁 Lock锁 等待唤醒机制 1    多线程 1.1     线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果 ...

  5. 缓存的有效期和淘汰策略【Redis和其他缓存】【刘新宇】

    缓存有效期与淘汰策略 有效期 TTL (Time to live) 设置有效期的作用: 节省空间 做到数据弱一致性,有效期失效后,可以保证数据的一致性 Redis的过期策略 过期策略通常有以下三种: ...

  6. java并发编程(三)----线程的同步

    在现实开发中,我们或多或少的都经历过这样的情景:某一个变量被多个用户并发式的访问并修改,如何保证该变量在并发过程中对每一个用户的正确性呢?今天我们来聊聊线程同步的概念. 一般来说,程序并行化是为了获得 ...

  7. [转载]MongoDB管理基础

    1.  启动和停止MongoDB: 执行mongod命令启动MongoDB服务器.mongod有很多可配置的选项,我们通过mongod --help可以查看所有选项,这里仅介绍一些主要选项:    - ...

  8. Spring项目集成ShiroFilter简单实现权限管理

    Shiros是我们开发中常用的用来实现权限控制的一种工具包,它主要有认证.授权.加密.会话管理.与Web集成.缓存等功能.我是从事javaweb工作的,我就经常遇到需要实现权限控制的项目,之前我们都是 ...

  9. Redis简单梳理及集群配置

    **REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统. Redis是一个开源的使用ANSI C语言编写.遵 ...

  10. 网络编程网络协议篇(osi七层协议)

    一 互联网的本质 咱们先不说互联网是如何通信的(发送数据,文件等),先用一个经典的例子,给大家说明什么是互联网通信. 现在追溯到八九十年代,当时电话刚刚兴起,还没有手机的概念,只是有线电话,那么此时你 ...