题目:http://codeforces.com/contest/1150/problem/D

老是想着枚举当前在给定字符串的哪个位置,以此来转移。

所以想对三个串分别建 trie 树,然后求出三个trie树上各选一个点的答案。那么从“在三个trie树的根,在给定字符串的0位置”开始扩展。

当然 TLE 了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
const int N=1e5+,M=;
int n,m,tot=,nw[],fa[M],c[M][],fl[M],q2[M];
char s[N];
struct Dt{
int x,y,z;
Dt(int x=,int y=,int z=):x(x),y(y),z(z) {}
bool operator< (const Dt &b)const
{
if(x!=b.x)return x<b.x;
if(y!=b.y)return y<b.y; return z<b.z;
}
bool operator== (const Dt &b)const
{return x==b.x&&y==b.y&&z==b.z;}
}qr[M],I;
struct Node{
Dt a;int ps;
Node(Dt a=I,int p=):a(a),ps(p) {}
bool operator< (const Node &b)const
{return a<b.a;}
};
queue<Node> q;
map<Dt,bool> mp;
void add(int &x,int w)
{
if(c[x][w])x=c[x][w];////if!!!!!
else{ c[x][w]=++tot; fa[tot]=x; x=tot;}
}
void get_fl(int rt)
{
int he=,tl=;
for(int i=;i<;i++)
if(c[rt][i])fl[c[rt][i]]=rt,q2[++tl]=c[rt][i];
else c[rt][i]=rt;
while(he<tl)
{
int k=q2[++he],pr=fl[k];
for(int i=;i<;i++)
if(c[k][i])fl[c[k][i]]=c[pr][i],q2[++tl]=c[k][i];
else c[k][i]=c[pr][i]; }
}
void cz(Dt cr,int ps)
{
for(int x=cr.x;x;x=fl[x])
for(int y=cr.y;y;y=fl[y])
for(int z=cr.z;z;z=fl[z])
if(!mp[cr]){mp[cr]=; q.push(Node(cr,ps));}
else return;
}
int main()
{
scanf("%d%d",&n,&m); scanf("%s",s+);
nw[]=; nw[]=; nw[]=;
char op,w;int d;
for(int i=;i<=m;i++)
{
cin>>op; scanf("%d",&d);
if(op=='+'){cin>>w;add(nw[d],w-'a');}
else nw[d]=fa[nw[d]];
qr[i]=Dt(nw[],nw[],nw[]);
}
for(int i=;i<=;i++)get_fl(i);
Dt cr=Dt(,,); mp[cr]=; q.push(Node(cr,));
while(q.size())
{
Node k=q.front();q.pop();
if(k.ps==n)continue;
k.ps++; q.push(k); int w=s[k.ps]-'a';
cr=k.a; cr.x=c[cr.x][w]; cz(cr,k.ps);
cr=k.a; cr.y=c[cr.y][w]; cz(cr,k.ps);
cr=k.a; cr.z=c[cr.z][w]; cz(cr,k.ps);
}
for(int i=;i<=m;i++)
puts(mp.count(qr[i])?"YES":"NO");
return ;
}

给定字符串的一个位置可能使得三个串都不能扩展。所以考虑不枚举字符串的每个位置来转移,而是做一个序列自动机。

令 dp[i][j][k] 表示三个地区分别匹配了前 i 、j、k 个字符的“最靠前位置”,如果值==n+1说明无解。

那么就可以使用序列自动机实现 2503 的DP了。就是 dp[i][j][k] = min( nxt[ dp[i-1][j][k] ][ c1[i] ] , nxt[ dp[i][j-1][k] ][ c2[j] ] , nxt[ dp[i][j][k-1] ][ c3[k] ] ) 。

对于一个询问,如果是 ' - ' ,DP数组不用改动。如果是 ' + ' ,固定该维, 2502 做一下DP即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
int Mn(int a,int b){return a<b?a:b;}
const int N=1e5+,M=,K=;
int n,lst[K],nxt[N][K],dp[M][M][M],l0,l1,l2;
char s[N];int c0[M],c1[M],c2[M];
int main()
{
n=rdn(); int Q=rdn();
scanf("%s",s+);
for(int i=;i<K;i++)
lst[i]=nxt[n+][i]=n+;
for(int i=n;i>=;i--)
{
for(int j=;j<K;j++) nxt[i][j]=lst[j];
if(i)lst[s[i]-'a']=i;
}
char op;int x,w;
while(Q--)
{
cin>>op; x=rdn()-;
if(op=='+')
{
cin>>op; w=op-'a';
if(x==)
{
c0[++l0]=w;
for(int i=;i<=l1;i++)
for(int j=;j<=l2;j++)
{
dp[l0][i][j]=nxt[dp[l0-][i][j]][w];
if(i)dp[l0][i][j]=
Mn(dp[l0][i][j],nxt[dp[l0][i-][j]][c1[i]]);//i not l1
if(j)dp[l0][i][j]=
Mn(dp[l0][i][j],nxt[dp[l0][i][j-]][c2[j]]);
}
}
if(x==)
{
c1[++l1]=w;
for(int i=;i<=l0;i++)
for(int j=;j<=l2;j++)
{
dp[i][l1][j]=nxt[dp[i][l1-][j]][w];
if(i)dp[i][l1][j]=
Mn(dp[i][l1][j],nxt[dp[i-][l1][j]][c0[i]]);
if(j)dp[i][l1][j]=
Mn(dp[i][l1][j],nxt[dp[i][l1][j-]][c2[j]]);
}
}
if(x==)
{
c2[++l2]=w;
for(int i=;i<=l0;i++)
for(int j=;j<=l1;j++)
{
dp[i][j][l2]=nxt[dp[i][j][l2-]][w];
if(i)dp[i][j][l2]=
Mn(dp[i][j][l2],nxt[dp[i-][j][l2]][c0[i]]);
if(j)dp[i][j][l2]=
Mn(dp[i][j][l2],nxt[dp[i][j-][l2]][c1[j]]);
}
}
}
else
{
if(x==)l0--; if(x==)l1--; if(x==)l2--;
}
puts(dp[l0][l1][l2]<=n?"YES":"NO");
}
return ;
}

CF 1150 D Three Religions——序列自动机优化DP的更多相关文章

  1. 异或序列 [set优化DP]

    也许更好的阅读体验 \(\mathcal{Description}\) 有一个长度为 \(n\)的自然数序列 \(a\),要求将这个序列分成至少 \(m\) 个连续子段 每个子段的价值为该子段的所有数 ...

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

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

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

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

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

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

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

    [BZOJ4032][HEOI2015]最短不公共子串(后缀自动机,序列自动机) 题面 BZOJ 洛谷 题解 数据范围很小,直接暴力构建后缀自动机和序列自动机,然后直接在两个自动机上进行\(bfs\) ...

  6. Subsequence(序列自动机模板题)

    题目链接:https://nanti.jisuanke.com/t/38232 题目大意:给你一个字符串,然后再给你m个字符串,然后问你在第一个字符串中不连续的子串能不能构成输入的子串. 具体思路:构 ...

  7. 【机器学习】支持向量机(SVM)的优化算法——序列最小优化算法(SMO)概述

    SMO算法是一一种启发式算法,它的基本思路是如果所有变量的解的条件都满足最优化问题的KKT条件,那么这个最优化问题的解就得到了.因为KKT条件是该优化问题的充分必要条件. 整个SMO算法包括两个部分: ...

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

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

  9. 牛客小白月赛12J(序列自动机)

    题目链接:https://ac.nowcoder.com/acm/contest/392/J 题目大意:给一个字符串s,然后在给出n个其他的字符串,判断每个字符串是否为s的子序列. 例: 输入: no ...

随机推荐

  1. flutter Container组件和Text组件

    在开始之前,我们先写一个最简单的入口文件:     后面,都是在这个结构的基础上面完成的. 由于Container组件和Text组件都是写在body里面的,所以下面,先将body抽离成一个组件的形式. ...

  2. [CSP-S模拟测试]:异或(树状数组+LCA)

    题目传送门(内部题21) 输入格式 第一行一个字符串$str$,表示数据类型.第二行一个正整数$k$,表示集合$K$的大小,保证$k>1$.接下来$k$行每行$k$个数,第$i$行第$j$个数表 ...

  3. 四两拨千斤,ARM是如何运作、靠什么赚钱的

    在智能手机.平板大行其道的今天,ARM这个名字我们几乎每天都要见到或者听到几次,作为编辑的我更是如此,每天涉及到的新闻总是或多或少跟ARM扯上关系,它还与Intel.AMD.NVIDA等公司有说不清道 ...

  4. appium移动端自动化测试的一些感想

    花了一个多月的时间来复习,学习appium+python+android的UI层的自动化测试. 从最开始的环境搭建,都后面运行脚本报错各类错,到优化脚本结构,基本上问题不断. 相比,selenium做 ...

  5. 小白学 Python 爬虫(26):为啥上海二手房你都买不起

    人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...

  6. 网络安全随笔 - Linux的netstat查看端口 0.0.0.0与127.0.0.1的区别

    linux运维都需要对端口开放查看  netstat 就是对端口信息的查看 # netstat -nltp p 查看端口挂的程序 [root@iz2ze5is23zeo1ipvn65aiz ~]# n ...

  7. Python 进阶_OOP 面向对象编程_静态方法和类方法

    目录 目录 静态方法 类方法 使用函数修饰符来声明静态方法和类方法 静态方法 静态方法仅是类中的函数, 不需要绑定实例, 也就是说静态方法的定义不需要传入 self 参数. 静态方法不属于类的某一个实 ...

  8. delphi vlc 安装bug 处理编译错误"0" is an invalid value for the "DebugInformation" parameter of the "DCC"

    处理编译错误"0" is an invalid value for the "DebugInformation" parameter of the "DCC" [摘要:http://blog.csdn ...

  9. WPF自定义控件(三)

    今天我们开始制作我们的按钮,主要的效果就是一个按钮正常状态.鼠标滑过.按下三态显示不同的图片. 首先我们需要给扩展按钮添加三个属性,分别是正常状态图片,鼠标滑过图片,按钮按下图片. 先贴出Button ...

  10. Java空对象模式

    在“空对象”模式中,空对象将替换NULL对象实例的检查.而不是检查一个空值,Null对象反映一个无关的关系(即什么也不做). 这种Null对象还可以用于在数据不可用时提供默认行为. 在空对象模式(Nu ...