[题目][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. 1.Ioc&DI和Spring

    1.面向对象回顾和案例 面向对象程序设计:1 2 3 4 案例分析: 需求分析: 报表功能:     报表服务类,检索数据,并生成图标     报表生成器类,生成不同格式的报表文件,例如PDF格式.H ...

  2. idea各种快捷键

    工作的的时候,如果不知道idea一些方便的快捷键会大大影响工作效率,今天打算看看这些小技巧: https://blog.csdn.net/linsongbin1/article/details/802 ...

  3. windows环境搭建禅道项目管理工具

    zentao官网的几个网址 http://www.zentao.net/ http://www.zentao.net/article-view-79863.html   搭建环境需要下载两个文件 1) ...

  4. idea+springboot+Mybatis搭建web项目

    使用idea+springboot+Mybatis搭建一个简单的web项目. 首先新建一个项目: 在这里选择Maven项目也可以,但是IDEA为我们提供了一种更方便快捷的创建方法,即Spring In ...

  5. JMeter 正则表达式提取器(二)

    引用名:  引用此数据-别名 正则表达式:  取值 模板: 表示使用提取到的第几个值:$-1$:表示取所有值$0$:表示随机取值$1$:表示取第1个$2$:表示取第二个以此类推:$n$:表示取第n个 ...

  6. epoll中坑人的地方再次学习

    https://blog.csdn.net/linuxheik/article/details/73294658

  7. zabbix--高级篇-监控docker服务(一)

    一,配置zabbix 客户端环境 rpm -ivh https://mirrors.aliyun.com/zabbix/zabbix//x86_64/zabbix-release-.el7.noarc ...

  8. PlayMaker 做成预制体

    把包含PlayMaker状态机的游戏物体做成预制体后,再编辑PlayMaker状态机的时候,会有两个选项 * Edit Prefab :编辑完成后预制体的PlayMaker状态机也会改变: * Edi ...

  9. LeetCode 222.完全二叉树的节点个数(C++)

    给出一个完全二叉树,求出该树的节点个数. 说明: 完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置.若最底 ...

  10. contiki源码阅读之mmem.c

    上次我们说了list,这次我们就借着mmem.c的代码来用一下这个链表. 代码目录是./core/lib/mmem.c 结构体定义如下 struct mmem { struct mmem *next; ...