序列自动机:

是一个处理子序列的自动机。就这样。

建造:(By猫老师:immoralCO猫)

s[]
next[][]
memset(next[n], -, <<);
for(int i = n; i; --i) {
memcpy(next[i - ], next[i], << );
next[i - ][s[i] - 'a'] = i;
}

nxt[][]数组就是第几个位置,序号为几的出边连接到第几个位置(位置是对应字符串的位置,其实并没用)

大概原理就是每当要循环到字符串中的一个位置,就把这个位置的连通性赋值给上一个节点编号,(可以理解,n个字符,其实是n条边,最多有n+1个节点在两边)

然后处理新来的字符i对于i-1号位置连通性的影响,那么,

编号从0~n,其中0号点就是根,dfs从0开始。

(不会的话,手动模拟就好了)

发现,当子序列中有重复元素的时候,nxt[i-1][s[i]-'a']=i一句可以将这种情况覆盖掉。

由于这些0~n号节点可以重复到达,当然最终到了n号点就是边界了。

所以dfs没有问题。而且大大节省了空间。

这样,我们可以只用有限的O(长度*|S|)的空间,来建造这棵树。

发现,这棵树好像trie啊~!!!!

其实差不多,一个子序列,一个子串。

操作也就和trie差不多了。

基本操作:

1.可以统计一个串本质不同的子序列的个数

序列自动机上可以是一棵树,树上每一个节点到根的路径上的边所代表的字符串就是所有的本质不同的子序列。

dfs树上扫一遍就好了。

2.可以查找一个子序列是否在这个字符串中出现过。

显然,dfs就可以。

3.也可以两个序列自动机一起dfs,找到所有公共子序列。

就比如说这个题:

(真是序列自动机板子题)

[FJOI2016]所有公共子序列问题

题目大意:给定两个字符串,求这两个串的所有公共子序列。

当输入的参量k=1的时候,按照字典序输出这些子序列,并输出个数。

当输入的参量k=0的时候,输出个数就可以。

注意,空字符串也是一个公共子序列。

分析:

裸裸裸裸的序列自动机。

开两个自动机,直接同时跑dfs就可以。

对于k=1,就要先走a,再走z,条件是两个都可以走,一遍用一个栈一样的字符串记录字符串。进入循环就输出即可。并且记录总数。

对于k=0,同理。

诶,怎么我的long long出了负数呢??

因为要高精。

诶,怎么我的高精MLE了呢????

因为要压位高精。

https://www.cnblogs.com/Miracevin/p/9031691.html

但是这个版本太弱了,很久以前写的。

所以,用结构体实现就比较方便了。结构体内置函数。

支持:高精加低精(因为要赋初值1(其实直接赋值也可以)),高精加高精,压位高精的输出。

没了。

看代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9;
const int N=;
const int L=;
const int K=;
int nxt1[N][L],nxt2[N][L];
char sta[N];
int top=-;
ll ans;
int la,lb,k;
char a[N],b[N];
struct Big{//压位结构体
int cur;
ll *s;
void init(){
s=new long long[];
for(int i=;i<;i++) s[i]=;
cur=;
}
void put(){
printf("%lld",s[cur]);
for(int i=cur-;i>=;i--) printf("%09lld",s[i]);
}
void add(ll k){
s[]+=k;
int i=;
while(s[i]>=mod) s[i+]+=s[i]/mod,s[i++]%=mod;
while(s[cur+]) cur++;
}
void Add(const Big& o){
ll i,r=max(cur,o.cur);
for(int i=;i<=r;i++){
s[i]+=o.s[i];
if(s[i]>=mod) s[i+]+=s[i]/mod,s[i]%=mod;
}
cur=min(r+,19ll);while(cur&&s[cur]==) cur--;
}
}dp[N][N];
bool vis[N][N];
void build1(){//建造序列自动机
memset(nxt1[la],-,sizeof nxt1[la]);
for(int i=la;i;i--){
memcpy(nxt1[i-],nxt1[i],sizeof nxt1[i]);
nxt1[i-][a[i]-'A']=i;
}
}
void build2(){
memset(nxt2[lb],-,sizeof nxt2[lb]);
for(int i=lb;i;i--){
memcpy(nxt2[i-],nxt2[i],sizeof nxt2[i]);
nxt2[i-][b[i]-'A']=i;
}
}
void dfs2(int x,int y){//dfs
if(vis[x][y]) return;
vis[x][y]=;
dp[x][y].init();
dp[x][y].add();
for(int i=;i<=;i++){
if(nxt1[x][i]!=-&&nxt2[y][i]!=-) {
dfs2(nxt1[x][i],nxt2[y][i]);
dp[x][y].Add(dp[nxt1[x][i]][nxt2[y][i]]);
}
}
}
ll dfs1(int x,int y){
printf("%s\n",sta);
ll cnt=;
for(int i=;i<=;i++){
if(nxt1[x][i]!=-&&nxt2[y][i]!=-) {
sta[++top]=i+'A';
cnt+=dfs1(nxt1[x][i],nxt2[y][i]);
sta[top--]=' ';
}
}
return cnt;
}
int main()
{
scanf("%d%d",&la,&lb);
scanf("%s",a+);scanf("%s",b+);
scanf("%d",&k);
build1();build2();
if(k==) {
dfs1(,);
}
dfs2(,);
dp[][].put();
return ;
}

序列自动机—— [FJOI2016]所有公共子序列问题的更多相关文章

  1. hunnu 11313 无重复元素序列的最长公共子序列转化成最长递增子序列 求法及证明

    题目:http://acm.hunnu.edu.cn/online/?action=problem&type=show&id=11313 湖师大的比赛,见我的另一篇水题题解,这里要说的 ...

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

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

  3. [csu/coj 1078]多个序列的最长公共子序列

    题意:给n个序列,同一个序列里面元素互不相同,求它们的最长公共子序列. 思路:任取一个序列,对于这个序列里面的两个数ai,aj(i<j),如果对于其它每一个序列,都出现过ai,aj,且ai在aj ...

  4. luogu4608 [FJOI2016]所有公共子序列问题

    题目描述: luogu loj 题解: 序列自动机(?)+高精+普及dp. 这个是猫老师的序列自动机(字符串从1开始): ]) { memset(t[n],-,sizeof(t[n])); ;i> ...

  5. 【LCS,LIS】最长公共子序列、单调递增最长子序列

    单调递增最长子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:4   描述 求一个字符串的最长递增子序列的长度如:dabdbf最长递增子序列就是abdf,长度为4   输入 ...

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

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

  7. 动态规划之最长公共子序列(LCS)

    转自:http://segmentfault.com/blog/exploring/ LCS 问题描述 定义: 一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则 ...

  8. [Data Structure] LCSs——最长公共子序列和最长公共子串

    1. 什么是 LCSs? 什么是 LCSs? 好多博友看到这几个字母可能比较困惑,因为这是我自己对两个常见问题的统称,它们分别为最长公共子序列问题(Longest-Common-Subsequence ...

  9. LCS(Longest Common Subsequence 最长公共子序列)

    最长公共子序列 英文缩写为LCS(Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已 ...

随机推荐

  1. JVM规范系列第3章:为Java虚拟机编译

    Oracle 的 JDK 包括两部分内容:一部分是将 Java 源代码编译成 Java 虚拟机的指令集的编译器,另一部分是用于Java 虚拟机的运行时环境. 第一部分应该说的是 Javac 这个前置编 ...

  2. 【javascript】详解javaScript的深拷贝

        前言: 最开始意识到深拷贝的重要性是在我使用redux的时候(react + redux), redux的机制要求在reducer中必须返回一个新的对象,而不能对原来的对象做改动,事实上,当时 ...

  3. Linux下防御DDOS攻击的操作梳理

    DDOS的全称是Distributed Denial of Service,即"分布式拒绝服务攻击",是指击者利用大量“肉鸡”对攻击目标发动大量的正常或非正常请求.耗尽目标主机资源 ...

  4. Samba共享目录的多用户权限设置案例

    下面根据实际工作中遇到的一个共享目录的多用户权限需求案例来说明下Samba用户权限的设置. 一.需求场景领导:李一(liyi)正式员工(zhengshiyuangong):刘二二(liuerer).于 ...

  5. 牛客第二场-J-farm-二维树状数组

    二维树状数组真的还挺神奇的,更新也很神奇,比如我要更新一个区域内的和,我们的更新操作是这样的 add(x1,y1,z); add(x2+1,y2+1,z); add(x1,y2+1,-z); add( ...

  6. sql-server安装

    ubuntu安装sql-server https://docs.microsoft.com/zh-cn/sql/linux/quickstart-install-connect-ubuntu?view ...

  7. 第三个Sprint ------第六天

    分数计算界面代码 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:a ...

  8. Install Jetty web server on CentOS 7 / RHEL 7

    http://www.eclipse.org/jetty/download.html http://www.eclipse.org/jetty/documentation/current/startu ...

  9. FreeMaker使用HashMap

    private Map<String, Object> variables; <input type="hidden" id="tongzhisbm&q ...

  10. Event事件2

    1,阻止默认行为: 2,事件监听 3,事件流之事件捕获 4,事件委托 阻止默认行为 浏览器中有很多默认行为,比如当点击a标签后,会发生链接的跳转.当点击鼠标的右键时, 会显示右键菜单等. 有些时候,浏 ...