【[TJOI2017]DNA】
[题目][https://www.lydsy.com/JudgeOnline/problem.php?id=4892]
好像用\(SAM\)做的都是\(dfs\)啊
其实这里也是搜索
如果用\(SAM\)来做非常好理解,就是从\(SAM\)上匹配这个字符串,允许有不超过三条转移边不一样
于是\(dfs\)做法非常显然了,就是爆搜这三条不一样的转移边在哪里,但是复杂度看起来好像很迷,可能是\(\binom{n}{3}\)也就是\(O(n^3)\)级别
但是由于很多情况下选择某一条转移甚至都无法在\(SAM\)上有一个长度为\(n\)的匹配,所以\(dfs\)非常的快
这里写的是一个\(bfs\),但是长得和\(dp\)有点像?
设\(f[i][j][k]\)表示在\(SAM\)上跑了\(i\)位跑到了\(j\)这个节点,\(k\)次个位置不一样是否可行,显然的转移就是枚举下一个是走\(A,C,G,T\)
发现这个数组可以滚动,之后就滚动好了
滚动的同时还需要滚动两个栈,用来存储有用的状态,其实就是广搜里的队列了
还有一个小剪枝,我们提前处理出每一个节点往下跑出来的最长路,我们可以根据这个快速判断出一个状态是否可行
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 200005
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
int Test,lst,cnt,num,n,top[2],tot,o;
struct St {int a,b;} st[2][maxn];
struct E{int v,nxt;} e[maxn<<1];
char S[maxn>>1],T[maxn>>1];
int son[maxn][4],fa[maxn],sz[maxn],len[maxn],head[maxn],mx[maxn],q[maxn],r[maxn],f[maxn][4];
inline void add(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
void dfs(int x) {for(re int i=head[x];i;i=e[i].nxt) dfs(e[i].v),sz[x]+=sz[e[i].v];}
inline int solve(char c) {if(c=='A') return 0;if(c=='C') return 1;if(c=='G') return 2;return 3;}
inline void ins(int c)
{
int f=lst,p=++cnt; lst=p;
len[p]=len[f]+1,sz[p]=1;
while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
if(!f) {fa[p]=1;return;}
int x=son[f][c];
if(len[f]+1==len[x]) {fa[p]=x;return;}
int y=++cnt;
len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
for(re int i=0;i<4;i++) son[y][i]=son[x][i];
while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
}
int main()
{
scanf("%d",&Test);
while(Test--)
{
scanf("%s",S+1);scanf("%s",T+1);
for(re int i=1;i<=cnt;i++)
r[i]=head[i]=mx[i]=len[i]=fa[i]=sz[i]=son[i][0]=son[i][1]=son[i][2]=son[i][3]=0;
top[0]=top[1]=0;
lst=cnt=1,num=0;
n=strlen(S+1);
for(re int i=1;i<=n;i++) S[i]=solve(S[i]),ins(S[i]);
for(re int i=2;i<=cnt;i++) add(fa[i],i); dfs(1);
num=tot=o=0;
for(re int i=1;i<=cnt;i++) head[i]=0;
for(re int i=1;i<=cnt;i++)
for(re int j=0;j<4;j++) if(son[i][j]) add(son[i][j],i),r[i]++;
for(re int i=1;i<=cnt;i++) if(!r[i]) q[++tot]=i;
for(re int i=1;i<=tot;i++)
for(re int j=head[q[i]];j;j=e[j].nxt)
{r[e[j].v]--; mx[e[j].v]=max(mx[e[j].v],mx[q[i]]+1);if(!r[e[j].v]) q[++tot]=e[j].v;}
n=strlen(T+1);
for(re int i=1;i<=n;i++) T[i]=solve(T[i]);
memset(f,0,sizeof(f));
st[0][++top[0]]=(St){1,0};
for(re int i=1;i<=n;i++,o^=1)
{
for(re int j=1;j<=top[o];j++)
f[st[o][j].a][st[o][j].b]=0;
top[o^1]=0;
for(re int j=1;j<=top[o];j++)
{
int x=st[o][j].a,y=st[o][j].b;
for(re int k=0;k<4;k++)
if(son[x][k]&&k!=T[i]&&y<3)
{
if(mx[son[x][k]]+i<n) continue;
if(!f[son[x][k]][y+1]) st[o^1][++top[o^1]]=(St){son[x][k],y+1},f[son[x][k]][y+1]=1;
}
int k=T[i];
if(!son[x][k]||mx[son[x][k]]+i<n) continue;
if(!f[son[x][k]][y]) st[o^1][++top[o^1]]=(St){son[x][k],y},f[son[x][k]][y]=1;
}
}
int ans=0;
for(re int i=2;i<=cnt;i++) if(f[i][0]||f[i][1]||f[i][2]||f[i][3]) ans+=sz[i];
printf("%d\n",ans);
}
return 0;
}
【[TJOI2017]DNA】的更多相关文章
- luogu题解 P3763 【[TJOI2017]DNA】
题目链接: https://www.luogu.org/problemnew/show/P3763 思路: 首先我们要用到Rabin-Karp哈希,其实就是这个: 若\(w_{str}\)=(\(a_ ...
- codeforces 217E 【Alien DNA】
倒序考虑每一个操作,对于一个操作$[l, r]$,他产生的影响区间将是$[r+1,r + r + l - 1]$,如果$r+l-1>K$的话,$K$之后的区间我们是不关心的. 暴力扫描这个区间 ...
- 【[TJOI2017]城市】
题目 好像\(noip\)之前做某雅礼的题的时候看到过这道题的数据范围增强版 当时那道题数据范围是\(3e5\)感觉神仙的一批 这道题数据范围\(5e3\)那岂不是可以\(O(n^2)\)水过 有一点 ...
- 【codeforces 520C】DNA Alignment
[题目链接]:http://codeforces.com/contest/520/problem/C [题意] 给你一个函数; 它的作用是评估两个字符串的相似程度; 评估的时候: 保持一个字符串不动, ...
- 【BZOJ 2323】 2323: [ZJOI2011]细胞 (DP+矩阵乘法+快速幂*)
2323: [ZJOI2011]细胞 Description 2222年,人类在银河系外的某颗星球上发现了生命,并且携带了一个细胞回到了地球.经过反复研究,人类已经完全掌握了这类细胞的发展规律: 这种 ...
- 【智能算法】超详细的遗传算法(Genetic Algorithm)解析和TSP求解代码详解
喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 文章声明 此文章部分资料和代码整合自网上,来源太多已经无法查明出处,如侵犯您的权利,请联系我删除. 00 目录 遗传算法定义 生 ...
- 【学时总结】 ◆学时·II◆ IDA*算法
[学时·II] IDA*算法 ■基本策略■ 如果状态数量太多了,优先队列也难以承受:不妨再回头看DFS-- A*算法是BFS的升级,那么IDA*算法是对A*算法的再优化,同时也是对迭代加深搜索(IDF ...
- 【复习笔记】重习 AC 自动机
发现已经忘了许多....于是复习一下 基础要点概况 AC 自动机基于 Trie 树 的结构,即构建 AC 自动机前需要先建 Trie. 一个状态中除了转移 \(\delta\) 之外还有失配指针 \( ...
- 【AR实验室】mulberryAR : ORBSLAM2+VVSION
本文转载请注明出处 —— polobymulberry-博客园 0x00 - 前言 mulberryAR是我业余时间弄的一个AR引擎,目前主要支持单目视觉SLAM+3D渲染,并且支持iOS端,但是该引 ...
随机推荐
- spring AOP正则表达式的几个问题
基于包名的正则表达式,是根据抽象父类的包名过滤,还是实现类的包名过滤, 还是抽象父类实现的接口的包名过滤? org.springframework.aop.aspectj.AspectJExpress ...
- py---------常用模块
一.认识模块? 什么是模块? 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1. 使用pytho ...
- java——极简handler机制
handler机制要做的事情: 1.把一堆从四面八方传来的message加到一个队列中,这个队列就是MessageQueue. 2.将MessageQueue中的队头Message取出,并使用这个me ...
- 2019.03.19 读书笔记 string与stringbuilder的性能
1 string与stringbuilder 并不是stringbuilder任何时候都在性能上占优势,在少量(大约个位数)的字符串时,并不比普通string操作快. string慢的原因不是stri ...
- Linux平台命令挂载U盘——实现数据共享
废话少说,一一道来,Linux中按照步骤来做就可以啦.(嵌入式平台) 1.先看看本地的mount信息 # mountrootfs on / type rootfs (rw)/dev/root on / ...
- Zookeeper配置Kafka
Zookeeper安装 解压:tar -zxvf zookeeper-3.4.5-cdh5.7.0.tar.gz -C ~/app/ 配置到环境变量: vi ~/.bash_profile expor ...
- [一点一滴.NET]前台线程和后台线程
前台线程和后台线程就是通过线程实例的属性IsBackground=true or false来区分的. 新建一个线程是默认是后台线程. 前台线程全部执行完之后,才退出进程. 进程退出,所有的后台线程全 ...
- jQuery.hover() 函数详解
hover()函数用于为每个匹配元素的hover事件绑定处理函数. hover事件就是鼠标悬停事件.此外,你还可以额外传递给事件处理函数一些数据. 此外,你可以为同一元素多次调用该函数,从而绑定多个事 ...
- java实现新旧版本号比较
项目中需要使用比较现在线上版本和新版本,然后新版本执行新方法,方法如下: /** * * @方法名称:comparaVersion * @内容摘要: <版本比较> * @param old ...
- MyBatis01--------概念
主程序 读取配置 主配置文件 SQL映射文件 1.什么是框架? ① 框架是一个应用程序的半成品 一个框架程序员可以配置的选择.选项越多,认为这款框架的可扩展性强. 面向 ...