序列自动机—— [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 称为已 ...
随机推荐
- JDK8 stream toMap() java.lang.IllegalStateException: Duplicate key异常解决(key重复)
测试又报bug啦 接到测试小伙伴的问题,说是一个接口不返回数据了,好吧,虽然不是我写的接口任务落到头上也得解决,本地调试了一下,好家伙,直接抛了个异常出来,这又是哪位大哥喝醉了写的代码... Exce ...
- vs2017安装
每次安装包都搞的很大,而且出各式各式的问题. 安装程序清单签名失败 运行'vs_Enterprise.exe'时,出现'安装程序清单签名失败'的错误,直接删除'vs_installer.opc'文件, ...
- Centos7下关于系统用户密码规则-运维笔记
针对Centos7下的系统用户的密码规则复杂度的设置,处于安全考虑,说明如下: 一.设置密码规则 1)密码长度.有效期 /etc/login.defs文件是当创建用户时的一些规划,比如创建用户时,是否 ...
- Redis Cluster集群知识学习总结
Redis集群解决方案有两个: 1) Twemproxy: 这是Twitter推出的解决方案,简单的说就是上层加个代理负责分发,属于client端集群方案,目前很多应用者都在采用的解决方案.Twem ...
- ubuntu系统升级和其他相关操作记录
之前在openstack中安装了ubuntu 12.04虚拟机,版本较低,需要升级为高版本.下面分享下升级过程: ubuntu系统升级操作:$ cat /etc/issueUbuntu 12.04.5 ...
- margin不生效问题
问题机型 魅族M353 Android 5.0.1 问题描述 设置了margin-top: 15px; 但是在该机型上不生效 解决方案 使用padding 替代 margin
- Linux内核分析——期中总结
期中总结 一.MOOC课程 (一)计算机是如何工作的 1.冯诺依曼体系结构的核心思想是存储程序计算机. 2.CPU在实际取指令时根据cs:eip来准确定位一个指令. 3.寄存器模式,以%开头的寄存器标 ...
- wuziqi
五子棋结对人崔保雪的博客连接http://www.cnblogs.com/nuoxiaomi/ 题目简介 我们实现了一个五子棋的软件,该软件由初始化模块.下棋操作模块.人机对战模块.人人对 ...
- elastic-search-kibana-in-docker-dotnet-core-app
[翻译] 使用ElasticSearch,Kibana,ASP.NET Core和Docker可视化数据 原文地址:http://www.dotnetcurry.com/aspnet/1354/e ...
- Linux (centos7) 防火墙命令
防火墙配置 CentOS 7默认使用的是firewall作为防火墙,这里改为iptables防火墙. firewall操作: # service firewalld status; #查看防火墙状态 ...