序列自动机:

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

建造:(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. 数组排列组合问题——BACKTRACKING

    BACKTRACKING backtracking(回溯法)是一类递归算法,通常用于解决某类问题:要求找出答案空间中符合某种特定要求的答案,比如eight queens puzzle(将国际象棋的八个 ...

  2. c#基础系列2---深入理解 String

    "大菜":源于自己刚踏入猿途混沌时起,自我感觉不是一般的菜,因而得名"大菜",于自身共勉. 扩展阅读:深入理解值类型和引用类型 基本概念 string(严格来说 ...

  3. 通过容器提交镜像(docker commit)以及推送镜像(docker push)笔记

    在本地创建一个容器后,可以依据这个容器创建本地镜像,并可把这个镜像推送到Docker hub中,以便在网络上下载使用. 查看镜像 [root@docker-test1 ~]# docker image ...

  4. Jmeter(非GUI模式)教程

    前言 使用非 GUI 模式,即命令行模式运行 JMeter 测试脚本能够大大缩减所需要的系统资源.优点如下:1.节约系统资源:无需启动界面,节约系统资源 2.便捷快速:仅需启动命令行,输入命令便可执行 ...

  5. BugPhobia休息篇章:Beta阶段第IX次Scrum Meeting前奏

    特别说明:此次Scrum Meeting不计入正式的Scrum Meeting,因此此次工作仅为第IX次Scrum Meeting的前奏,而笔者也首次采用休息篇章作为子命题   0x01 :Scrum ...

  6. SprngMVC源码学习

    运行helloWorld示例进入调试界面. DispatcherServlet:前端控制器 DispatcherServlet.doDispatch(HttpServletRequest, HttpS ...

  7. ASP.NET MVC4学习笔记

    一.MVC简介

  8. linux的LNMP架构介绍、MySQL安装、PHP安装

    LNMP架构介绍 和LAMP唯一不同的是,LNMP中的N指的是Nginx(类似于Apache的一种web服务软件).目前这种环境的应用也非常多.Nginx设计的初衷是提供一种快速.高效.多并发的Web ...

  9. centos 7 修改系统屏幕分辨率

    centos 7 修改系统屏幕分辨率,命令方式和图形方式的修改方法. 命令:xrandr 通过命令 xrandr 修改系统的分辨率,输入xrandr: bash [admin@localhost ~] ...

  10. python2.7.x的字符串编码到底什么鬼?(中文和英文的处理)

    一直以来我其实一直对python的编码弄得非常晕,能正常编码,也能处理一些情况.但是始终不明白有些问题究竟为何出,原因是什么,为什么要这样用. 今天晚上正好好好研究了一番解答了自己心中的困惑. Q:p ...