[题目][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】的更多相关文章

  1. luogu题解 P3763 【[TJOI2017]DNA】

    题目链接: https://www.luogu.org/problemnew/show/P3763 思路: 首先我们要用到Rabin-Karp哈希,其实就是这个: 若\(w_{str}\)=(\(a_ ...

  2. codeforces 217E 【Alien DNA】

    倒序考虑每一个操作,对于一个操作$[l, r]$,他产生的影响区间将是$[r+1,r + r + l - 1]$,如果$r+l-1>K$的话,$K$之后的区间我们是不关心的. 暴力扫描这个区间 ...

  3. 【[TJOI2017]城市】

    题目 好像\(noip\)之前做某雅礼的题的时候看到过这道题的数据范围增强版 当时那道题数据范围是\(3e5\)感觉神仙的一批 这道题数据范围\(5e3\)那岂不是可以\(O(n^2)\)水过 有一点 ...

  4. 【codeforces 520C】DNA Alignment

    [题目链接]:http://codeforces.com/contest/520/problem/C [题意] 给你一个函数; 它的作用是评估两个字符串的相似程度; 评估的时候: 保持一个字符串不动, ...

  5. 【BZOJ 2323】 2323: [ZJOI2011]细胞 (DP+矩阵乘法+快速幂*)

    2323: [ZJOI2011]细胞 Description 2222年,人类在银河系外的某颗星球上发现了生命,并且携带了一个细胞回到了地球.经过反复研究,人类已经完全掌握了这类细胞的发展规律: 这种 ...

  6. 【智能算法】超详细的遗传算法(Genetic Algorithm)解析和TSP求解代码详解

    喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 文章声明 此文章部分资料和代码整合自网上,来源太多已经无法查明出处,如侵犯您的权利,请联系我删除. 00 目录 遗传算法定义 生 ...

  7. 【学时总结】 ◆学时·II◆ IDA*算法

    [学时·II] IDA*算法 ■基本策略■ 如果状态数量太多了,优先队列也难以承受:不妨再回头看DFS-- A*算法是BFS的升级,那么IDA*算法是对A*算法的再优化,同时也是对迭代加深搜索(IDF ...

  8. 【复习笔记】重习 AC 自动机

    发现已经忘了许多....于是复习一下 基础要点概况 AC 自动机基于 Trie 树 的结构,即构建 AC 自动机前需要先建 Trie. 一个状态中除了转移 \(\delta\) 之外还有失配指针 \( ...

  9. 【AR实验室】mulberryAR : ORBSLAM2+VVSION

    本文转载请注明出处 —— polobymulberry-博客园 0x00 - 前言 mulberryAR是我业余时间弄的一个AR引擎,目前主要支持单目视觉SLAM+3D渲染,并且支持iOS端,但是该引 ...

随机推荐

  1. pip 安装库的时候使用豆瓣镜像 提升效率

    由于众所周知的原因,国内网络环境始终处于水深火热之中,python库的安装也不例外. 比如在安装 PyQt5-tools 的时候,网速奇慢无比. 好在国内有不少镜像服务源,以豆瓣为例,网速突飞猛进 使 ...

  2. mysql初始化

    注意:--install前,必须用mysql启动命令的绝对路径 # 制作MySQL的Windows服务,在终端执行此命令: mysqld --install # 移除MySQL的Windows服务,在 ...

  3. 移动测试之appium+python 导出报告(六)

    下载 HTMLTestRunner.py python3可以参考这个地址 这是针对Python2.7版本 test.py from appium import webdriver import tim ...

  4. PlayMaker 设置颜色 Set Materia lColor

    1. 指定一个游戏对象,Color处设为红色,执行这个行为后就把游戏对象的材质变为了红色: 2. Color也可以使用一个弄好的Color类型的变量,如下图:Color处用了一个提前设置好的变量

  5. (转)ssh-keygen 中文手册

    ssh-keygen 中文手册 原文:http://www.jinbuguo.com/openssh/ssh-keygen.html 实例:http://blog.csdn.net/yl_1314/a ...

  6. jemeter+badboy录制脚本

    Jmeter 是一个非常流行的性能测试工具,虽然与LoadRunner相比有很多不足,比如:它结果分析能力没有LoadRunner详细:很它的优点也有很多: l       开源,他是一款开源的免费软 ...

  7. WPF的组成架构

    Windows呈现基础(Windows Presentation foundation,WPF)是微软新一代图形系统,运行,NET Framework3.0架构下,为用户界面.2D/3D图形.文档和媒 ...

  8. c#获取目录

    获取程序目录 string s = System.IO.Directory.GetCurrentDirectory(); Console.WriteLine(s);// C:\Users\r-\doc ...

  9. vue的计算和监视属性,附一小实例

    1. 计算属性 在computed属性对象中定义计算属性的方法 在页面中使用{{方法名}}来显示计算的结果 2. 监视属性: 通过通过vm对象的$watch()或watch配置来监视指定的属性 当属性 ...

  10. Spring-cloud微服务 Eureka学习教程-分布式搭建EurekaServer、EurekaClient+Ribbon(中级)

    我们这里只有一台服务器,所以我们先仿集群搭建. 完整demo项目代码:https://github.com/wades2/EurekaDemo2 在这之前我们先分析分析Eureka相比其他注册中心的好 ...