题目: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. java 通过反射获取类属性结构,类方法,类父类及其泛型,类,接口和包

    首先自定义三个类 package reflection1; public interface MtInterface { void info(); } package reflection1; imp ...

  2. vue工程本地代码请求http发生跨域提示错误解决方法

    这个可以使用代理进行跨域,这样看来跨域的方法就有几种了,对于iframe中的用postmassage,对于vue工程中的跨域则使用代理模式. 代理模式配置如下: 在config文件夹下找到index. ...

  3. WORM Worm worm 毛毛虫爬树爬树~

    对于动态规划,我也就不多说了.因为还不会, 每个题都不一样,但大致原则是一样的.抓住题意, 本题:n棵树,毛毛虫在m分钟内从p到t的路线种数,毛毛虫只可以向左右相邻位置走. 中心代码: for(i = ...

  4. 新建工程spring boot

    新建工程spring boot 使用Maven管理, 在官网(http://atart.spring.io)下载demo后,加入依赖 <dependency>         <gr ...

  5. [CSP-S模拟测试]:虎(DFS+贪心)

    题目传送门(内部题15) 输入格式 第一行一个整数$n$,代表点数接下来$n-1$行,每行三个数$x,y,z$,代表点$i$与$x$之间有一条边,若$y$为$0$代表初始为白色,否则为黑色,若$z$为 ...

  6. day 84 Xadmin组件之构建表单数据

    一 .先设置一些相关配置 1. 创建数据库模型. 在app01 下创建 from django.db import models # Create your models here. class Au ...

  7. Java + selenium 元素定位(2)之By LinkText/PartialLinkText

    本章介绍的两种方法都是对于网页上的文字链接的定位操作.根据名字,我们就可以看出来,这两者其实很相似,那么他们的不同在哪里呢. By LinkText()方法,是对一个的网页超链接,我们所需要输入的关键 ...

  8. python使用消息队列RabbitMq(进阶)

    import pika connection = pika.BlockingConnection(pika.ConnectionParameters( 'localhost')) channel = ...

  9. HTML表单实例

    HTML表单 表单用于搜集不同类型的用户输入,表单由不同类型的标签组成,实现一个特定功能的表单区域(比如:注册), 首先应该用<form>标签来定义表单区域整体,在此标签中再使用不同的表单 ...

  10. “希希敬敬对”队软件工程第九次作业-beta冲刺第六次随笔

    “希希敬敬对”队软件工程第九次作业-beta冲刺第六次随笔 队名:  “希希敬敬对” 龙江腾(队长) 201810775001 杨希                   201810812008 何敬 ...