题意:

给一个1e5的串str,然后有三个起始空串,不超过1000次操作,对三个字符串的一个尾部加一个字符或者减一个字符,保证每个字符不会超过250

每次操作之后询问你这三个串是不是可以组成str的子序列,

比如ab,cd,ef可以组成acgbdef的子序列

思路:

dp[i][j][k]为三个串分别匹配到i,j,k的时候组成的子序列的最后一个字符在str中的位置,如果dp[strlen(str1)][strlen(str2)][strlen(str3)]>n则输出no

对每一次询问我们可以处理出dp[i][j][k],

用序列自动机加速,nx[i][j]表示str中i位置的下一个字符j出现在什么位置(不包括i),没出现则为n+1

则状态转移方程

if(i)dp[i][j][k] = min(dp[i][j][k],nx[dp[i-1][j][k]][v[1][i-1]-'a']);
if(j)dp[i][j][k] = min(dp[i][j][k],nx[dp[i][j-1][k]][v[2][j-1]-'a']);
if(k)dp[i][j][k] = min(dp[i][j][k],nx[dp[i][j][k-1]][v[3][k-1]-'a']);

注意序列自动机要同样处理处nx[0][j]和nx[n+1][j],因为状态转移方程中可能会出现

复杂度O(250^3)

但这一题有q次询问,而且三个串在不停改变,我们不能每次都250^3处理,

当操作为“+”的时候,如果添加的是str1,若str1的长度由m变为m+1,可以发现,dp方程改变的只有dp[m+1][j][k],而其他的都没有改变(因为只是在尾部操作)

所以我们对每一次询问可以O(250^2)更新dp数组

而当操作为"-"的时候,我们并不需要更新dp数组,因为我们只能用到dp[m-1][j][k],而这之前已经处理好了,我们下一次“+”的时候,自然会覆盖dp[m][j][k]

所以总的复杂度为$O(26n+250^2q)$

代码:

题解的写法学会了✔

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional> #define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1
#define lowbit(x) ((x)&(-x)) using namespace std; typedef double db;
typedef long double ldb;
typedef long long ll;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL; const db eps = 1e-;
const int mod = 1e9+;
const int maxn = 1e6+;
const int maxm = 2e6+;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0); int n, q;
int dp[][][];
vector<char>v[];
int nx[maxn][];
char str[maxn];
void init(){
for(int i = ; i < ; i++){
nx[n][i] = n+;
nx[n+][i]=n+;
}
for(int i = n-; i >= ; i--){
for(int j = ; j < ; j++){
if(str[i+]-'a'==j){
nx[i][j] = i+;
}
else nx[i][j] = nx[i+][j];
}
}
}int mi[],mx[];
int main(){
scanf("%d %d" ,&n, &q);
scanf("%s",str+);
init();
while(q--){
char op[];
scanf("%s",op+);
int x;
scanf("%d",&x);
if(op[]=='+'){
char gao[];
scanf("%s",gao+);
char c = gao[];
v[x].pb(c); for(int i = ; i <= ; i++){
mi[i] = ;
mx[i] = v[i].size();
}
mi[x] = mx[x];
for(int i = mi[]; i <= mx[]; i++){
for(int j = mi[]; j <= mx[]; j++){
for(int k = mi[]; k <= mx[]; k++){
if(i+j+k==)continue;
dp[i][j][k] = n+;
if(i)dp[i][j][k] = min(dp[i][j][k],nx[dp[i-][j][k]][v[][i-]-'a']);
if(j)dp[i][j][k] = min(dp[i][j][k],nx[dp[i][j-][k]][v[][j-]-'a']);
if(k)dp[i][j][k] = min(dp[i][j][k],nx[dp[i][j][k-]][v[][k-]-'a']);
}
}
} }
else{ v[x].pop_back();
}
if(dp[v[].size()][v[].size()][v[].size()]<=n){
printf("YES\n");
}
else printf("NO\n");
}
return ;
}
/*
*/

Codeforces 1050D Three Religions (dp+序列自动机)的更多相关文章

  1. PTA L3-020 至多删三个字符 (序列dp/序列自动机)

    给定一个全部由小写英文字母组成的字符串,允许你至多删掉其中 3 个字符,结果可能有多少种不同的字符串? 输入格式: 输入在一行中给出全部由小写英文字母组成的.长度在区间 [4, 1] 内的字符串. 输 ...

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

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

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

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

  4. 洛谷P4608 [FJOI2016]所有公共子序列问题 【序列自动机 + dp + 高精】

    题目链接 洛谷P4608 题解 建个序列自动机后 第一问暴搜 第二问dp + 高精 设\(f[i][j]\)为两个序列自动机分别走到\(i\)和\(j\)节点的方案数,答案就是\(f[0][0]\) ...

  5. BZOJ4032 [HEOI2015]最短不公共子串 【后缀自动机 + 序列自动机 + dp】

    题目链接 BZOJ4032 题解 首先膜\(hb\) 空手切神题 一问\(hash\),二问枚举 三问\(trie\)树,四问\(dp\) 南二巨佬神\(hb\) 空手吊打自动机 \(orz orz ...

  6. BZOJ4032[HEOI2015]最短不公共子串——序列自动机+后缀自动机+DP+贪心

    题目描述 在虐各种最长公共子串.子序列的题虐的不耐烦了之后,你决定反其道而行之. 一个串的“子串”指的是它的连续的一段,例如bcd是abcdef的子串,但bde不是. 一个串的“子序列”指的是它的可以 ...

  7. BZOJ4416 [Shoi2013]阶乘字符串 【序列自动机 + 状压dp】

    题目链接 BZOJ4416 题解 建立序列自动机,即预处理数组\(nxt[i][j]\)表示\(i\)位置之后下一个\(j\)出现的位置 设\(f[i]\)表示合法字符集合为\(i\)的最短前缀,枚举 ...

  8. 后缀自动机&序列自动机综合

    好像序列自动机还没有写过- 串长为n的串共有n+1个节点,除了串中的n个节点,还有一个空的根节点放在串首.每个节点至多有26条出边,每条边连向它之后的第一个字符. 串中的任意一个子序列对应了一条根到某 ...

  9. 后缀自动机/回文自动机/AC自动机/序列自动机----各种自动机(自冻鸡) 题目泛做

    题目1 BZOJ 3676 APIO2014 回文串 算法讨论: cnt表示回文自动机上每个结点回文串出现的次数.这是回文自动机的定义考查题. #include <cstdlib> #in ...

随机推荐

  1. beetlex网关之聚合和url请求过虑

    在这里主要介绍beetlex应用网关的两个插件,分别是聚合和url请求过虑.通过聚合插件可以把整合多个请求的数据来应答请求端,而Url请求过虑同可以拒绝一些有非常关键字的请求. 请求聚合 在网关服务中 ...

  2. Java之File类用法总结

    File类概述:文件和文件目录路径的抽象表达形式,与平台无关.1.File能新建.删除.重命名文件和目录,但File不能访问文件内容本身.如果需要访问文件内容本身,则需要使用输入/输出流.2.想要在J ...

  3. python如何计算程序(代码块)的运行时间?

    1.引入time模块 2.调用time模块的time()函数 :用来获取当前的时间,返回的单位是秒 # 引入一个time模块, * 表示time模块的所有功能, # 作用: 可以统计程序运行的时间 f ...

  4. 集合下篇—Map和Set 源码分析

    Map Map不同于Collection集合,Map存放的是键值对,且键不能重复 1 .HashMap (底层是哈希表,Java中用链表的数组实现,存取顺序不一致) 这篇博客主要讲集合的,哈希表这样的 ...

  5. Alibaba Nacos 服务发现组件集群部署

    前面学习了单机模式下的启动,生产环境中部署nacos肯定是使用集群模式cluster保证高可用. 官方文档的集群部署推荐使用VIP+域名模式,把所有服务列表放到一个vip下面,然后挂到一个域名下面. ...

  6. 高通量计算框架HTCondor(五)——分布计算

    目录 1. 正文 1.1. 任务描述文件 1.2. 提交任务 1.3. 返回结果 2. 相关 1. 正文 1.1. 任务描述文件 前文提到过,HTCondor是通过condor_submit命令将提交 ...

  7. 【模板整理】Tarjan

    有向图强连通分量 int tot,low[N],dfn[N],scc[N],sccno; int st[N],top,vis[N]; void tarjan(int u){ int v; low[u] ...

  8. [洛谷P4178] Tree (点分治模板)

    题目略了吧,就是一棵树上有多少个点对之间的距离 \(\leq k\) \(n \leq 40000\) 算法 首先有一个 \(O(n^2)\) 的做法,枚举每一个点为起点,\(dfs\) 一遍可知其它 ...

  9. 《爬虫学习》(四)(使用lxml,bs4库以及正则表达式解析数据)

    1.XPath: XPath(XML Path Language)是一门在XML和HTML文档中查找信息的语言,可用来在XML和HTML文档中对元素和属性进行遍历. 工具:扩展商店里搜索:XPath ...

  10. pip install 清华源加速

    经常要通过pip install安装需要的包,但是每当下载的文件比较大时,网速不够快,会导致报错.所以采用清华源来加速 清华大学开源软件镜像站 https://mirrors.tuna.tsinghu ...