序列自动机

好像很高端的样子。。。

其实真的很简单。。。

序列自动机只有当数的类型比较少的时候才适用,一般出现字符串中,所以我们不妨设我们要处理的为字符串$A$

然后我们只需要记住第$i$个位置后字母$j$最早出现的位置即可。

就是这么简单

时间复杂度$O(26N)$

序列自动机的功能就是能遍历所有的子序列

好像非常冷门的样子。。。。。。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional>
#include<deque>
#include<cctype>
#include<climits>
#include<complex>
//#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj

using namespace std;

typedef long long LL;
typedef double DB;
typedef pair<int,int> PII;
typedef complex<DB> CP;

#define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define fill(a,l,r,v) fill(a+l,a+r+1,v)
#define re(i,a,b)  for(i=(a);i<=(b);i++)
#define red(i,a,b) for(i=(a);i>=(b);i--)
#define ire(i,x) for(typedef(x.begin()) i=x.begin();i!=x.end();i++)
#define fi first
#define se second
#define m_p(a,b) make_pair(a,b)
#define p_b(a) push_back(a)
#define SF scanf
#define PF printf
#define two(k) (1<<(k))

template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}

const DB EPS=1e-9;
inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
const DB Pi=acos(-1.0);

inline int gint()
  {
        int res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!=‘-‘ && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z==‘-‘){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-‘0‘,z=getchar());
        return (neg)?-res:res;
    }
inline LL gll()
  {
      LL res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!=‘-‘ && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z==‘-‘){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-‘0‘,z=getchar());
        return (neg)?-res:res;
    }

const int maxN=500000;
const int maxs=26;

struct sequence_automation
  {
      struct Tnode
        {
            int ch[maxs+1],fail;
            inline Tnode(){mmst(ch,0);fail=0;}
        }a[maxN+100];int MID;
      int last[maxs+1];
      inline int newnode(){a[++MID]=Tnode();return MID;}
      inline void clear(){MID=0;mmst(last,0);last[maxs]=newnode();}
      inline void add(int x)
        {
            int i,o=newnode();
            re(i,0,maxs)
              for(int p=last[i];p && !a[p].ch[x];p=a[p].fail)a[p].ch[x]=o;
            a[o].fail=last[x],last[x]=o;
        }
      inline void insert(char *s)
        {
            int i,len=strlen(s+1);
            clear();
            re(i,1,len)add(s[i]-‘a‘);
        }
  };

时间: 2024-08-29 11:20:34

序列自动机的相关文章

BZOJ 4032 HEOI2015 最短不公共子串 后缀自动机+序列自动机+BFS

题目大意:给定字符串A和B,求A最短的子串/子序列S满足S不是B的子串/子序列 这题真TM有毒*2 搞法类似这道题 然后子串是后缀自动机 子序列自然就是序列自动机了= = 每更新一个x节点时所有没有x的后继的节点都连向这个节点 每个节点的parent是这个字母上一次出现的位置 每个字母记录最后一次出现的位置 更新指针时沿着parent指针撸一遍就行了 #include <cstdio> #include <cstring> #include <iostream> #in

Nowcoder contest 392 J (模板题)【序列自动机】

<题目链接> 题目大意:给你一个母串A,然后进行q次询问,每次询问给定一个长度不超过母串的字符串,问你这个字符串是否是母串的子串. 解题分析:序列自动机模板题.本题的思想就是考虑贪心的去匹配,我们希望当前匹配到的位置越靠前越好.所以对于母串每一位都记一下下一次出现某个字符的位置.匹配的时候从第零位(虚根)开始,如果能一直匹配下去就是$Yes$ ,否则就是 $No$,这些操作就是用序列自动机简单实现. 单次查询的复杂度是$O(|B_i|)$ 的,序列自动机预处理的复杂度是 $O(26|A|)$的

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

题目:http://codeforces.com/contest/1150/problem/D 老是想着枚举当前在给定字符串的哪个位置,以此来转移. 所以想对三个串分别建 trie 树,然后求出三个trie树上各选一个点的答案.那么从“在三个trie树的根,在给定字符串的0位置”开始扩展. 当然 TLE 了. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #

杭电多校HDU 6586 String(序列自动机 贪心)题解

题意: 给你一个串,现需要你给出一个子序列,满足26个约束条件,\(len(A_i) >= L_i\) 且 \(len(a) <= R_i\), \(A_i\)为从a到z的26个字母. 思路: 先用序列自动机(?)构造出某个位置后每个字母的个数,每个字母 的第一个位置. 然后每次贪心地加入最小的字符,加入的条件为当前字母加入后,后面的字符满足剩余的条件. 即剩余的字母在不超R_i的情况下能构成k长度的串,剩余的字母\(A_i+\)已拿取字母\(A_i >= L_i\)且满足\(L_i\)

序列自动机 浅谈

其实这个东西真的算自动机吗?好像还真的符合自动机的定义啊: 我将在下面用人话来定义序列自动机,并不像某度某科一样不说人话: 设一个字符集S,nxt[i][j]表示第i个位置往后第一个j元素出现的位置: 这个nxt数组可以O(n)的求出来,可以自行验证: for(int i=n-1;i>=0;--i){ for(int j=1;j<=26;++j) nxt[i][j]=nxt[i+1][j]; nxt[i][s[i+1]-'a'+1]=i+1; } 我们会发现一个神奇的事情:这是一个DAG! 她

浅谈序列自动机

简介 序列自动机是一个可以快速判断字符串\(t\)是否是字符串\(s\)的子串的一个算法. 构造 对\(s\)构造序列自动机,使用\(Nxt_{i,j}\)代表从第\(i\)个位置开始,字符\(j\)出现的第一个位置.我们倒着遍历更新即可. int nxt[N][27]; void init(char *s){ int l=strlen(s); for(int i=0;i<26;i++) nxt[l][i]=INF; for(int i=l-1;i>=0;i--){ for(int j=0;j

C - Obtain The String 序列自动机

传送门:https://vjudge.net/contest/361562#problem/C 题意 多组样例,给你一个串s和串t还有一个空串x,要求往x里添加s的子序列,使x变为t,求添加次数. 思路 使用序列自动机狗仔串s的nxt数组,把整个t串进行匹配,当失配的时候,把前面已经匹配成功的部分当成一次子序列的添加,再从当前失配位置从头匹配,如果还是匹配失败则无法完成输出-1. AC代码 #include<iostream> #include<string.h> using na

序列自动机裸题(南昌邀请赛M)

各种自动机(待补) Give a string SS and NN string T_iTi? , determine whether T_iTi? is a subsequence of SS. If ti is subsequence of SS, print YES,else print NO. If there is an array \lbrace K_1, K_2, K_3,\cdots, K_m \rbrace{K1?,K2?,K3?,?,Km?} so that 1 \le K_

2019 Multi-University Training Contest 1 String(序列自动机+贪心)

题意:给你一个字符串 现在要你找出一个长度为k的字典序最小的子序列 且要求每个字母出现的个数要满足要求 思路:我们可以贪心构造每一位字符 优先放置字典序更小的字符 判断是否合法即可 #include <bits/stdc++.h> using namespace std; const double pi = acos(-1.0); const int N = 1e5+7; const int inf = 0x3f3f3f3f; const double eps = 1e-6; typedef