序列自动机—— [FJOI2016]所有公共子序列问题
序列自动机:
是一个处理子序列的自动机。就这样。
建造:(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]所有公共子序列问题的更多相关文章
- hunnu 11313 无重复元素序列的最长公共子序列转化成最长递增子序列 求法及证明
题目:http://acm.hunnu.edu.cn/online/?action=problem&type=show&id=11313 湖师大的比赛,见我的另一篇水题题解,这里要说的 ...
- 洛谷P4608 [FJOI2016]所有公共子序列问题 【序列自动机 + dp + 高精】
题目链接 洛谷P4608 题解 建个序列自动机后 第一问暴搜 第二问dp + 高精 设\(f[i][j]\)为两个序列自动机分别走到\(i\)和\(j\)节点的方案数,答案就是\(f[0][0]\) ...
- [csu/coj 1078]多个序列的最长公共子序列
题意:给n个序列,同一个序列里面元素互不相同,求它们的最长公共子序列. 思路:任取一个序列,对于这个序列里面的两个数ai,aj(i<j),如果对于其它每一个序列,都出现过ai,aj,且ai在aj ...
- luogu4608 [FJOI2016]所有公共子序列问题
题目描述: luogu loj 题解: 序列自动机(?)+高精+普及dp. 这个是猫老师的序列自动机(字符串从1开始): ]) { memset(t[n],-,sizeof(t[n])); ;i> ...
- 【LCS,LIS】最长公共子序列、单调递增最长子序列
单调递增最长子序列 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 求一个字符串的最长递增子序列的长度如:dabdbf最长递增子序列就是abdf,长度为4 输入 ...
- 后缀自动机&序列自动机综合
好像序列自动机还没有写过- 串长为n的串共有n+1个节点,除了串中的n个节点,还有一个空的根节点放在串首.每个节点至多有26条出边,每条边连向它之后的第一个字符. 串中的任意一个子序列对应了一条根到某 ...
- 动态规划之最长公共子序列(LCS)
转自:http://segmentfault.com/blog/exploring/ LCS 问题描述 定义: 一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则 ...
- [Data Structure] LCSs——最长公共子序列和最长公共子串
1. 什么是 LCSs? 什么是 LCSs? 好多博友看到这几个字母可能比较困惑,因为这是我自己对两个常见问题的统称,它们分别为最长公共子序列问题(Longest-Common-Subsequence ...
- LCS(Longest Common Subsequence 最长公共子序列)
最长公共子序列 英文缩写为LCS(Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已 ...
随机推荐
- KVM虚拟机管理——虚拟机克隆
1. 概述2. 部署基本操作系统虚拟机3. 配置虚拟机3.1 修改/etc/sysconfig/network3.2 删除/etc/sysconfig/network-scripts/ifcfg-et ...
- squid代理http和https方式上网的操作记录
需求说明:公司IDC机房有一台服务器A,只有内网环境:192.168.1.150现在需要让这台服务器能对外访问,能正常访问http和https请求(即80端口和443端口)操作思路:在IDC机房里另找 ...
- restfull环境搭建-helloword
原文地址:http://blog.csdn.net/u013158799/article/details/39758341 1. REST和RESTful Web Services的简要说明 REST ...
- C程序设计实践教学提示
实践教学要点:实验重心应放在实验室之外,重在实验准备 对实验题目的分析是一个复杂的工作,很发时间的,如全部放在实验上机时来完成,是不现实的.(特别是后面实验的难度增大,或实验代码增多的情况下),而且, ...
- 作业6-COSPLAY孩子他家长
为了我提高我女儿的数学能力,我以下我会根据我想要的功能做出相应的解决方案,为了孩子,父母也可以想的比老师周到.可怜天下父母心. 编号. 名称. ...
- 开源RabbitMQ操作组件
开源RabbitMQ操作组件 对于目前大多的.NET项目,其实使用的技术栈都是差不多,估计现在很少用控件开发项目的了,毕竟一大堆问题.对.NET的项目,目前比较适合的架构ASP.NET MVC,ASP ...
- linux和Mac上安装composer
使用命令行方式,可以直接使用下面的命令,顺序执行: php -r "copy ('https://getcomposer.org/installer','composer-setup.php ...
- Activiti Rest API tutorial
http://192.168.66.182:8080/activiti-rest/service/repository/deployments/ {"data":[{"i ...
- angular4 组件通讯、生命周期
主要通讯形式 父组件通过属性绑定到子组件,子组件通过事件传递参数到父组件 父组件通过局部变量获取子组件的引用 父组件使用@ViewChild获取子组件的引用 两个不相关联的组件使用中间人模式交互 终极 ...
- HMM模型学习笔记(前向算法实例)
HMM算法想必大家已经听说了好多次了,完全看公式一头雾水.但是HMM的基本理论其实很简单.因为HMM是马尔科夫链中的一种,只是它的状态不能直接被观察到,但是可以通过观察向量间接的反映出来,即每一个观察 ...