[题目][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. 查看Python支持的.whl文件版本

    AMD64 import pip._internal print(pip._internal.pep425tags.get_supported()) WIN32 import pip print(pi ...

  2. javascript判断input框只能输入数字的方法

    javascript 只允许输入数字有很多方法,总结如下 1,只允许输入数字和小数点. <input onKeypress="return (/[\d.]/.test(String.f ...

  3. Murano Service Architecture Introducation

    1. Murano Project Mission From the third-party tool developer’s perspective, the application catalog ...

  4. go语言初始化内部结构体3中方式

    package main import ( "fmt" ) type User struct { Id int Name string Age int } type Manger ...

  5. Supervised learning demo

    监督学习案例 规范 假设函数: 使用h(hypothesis, 假设)表示 输入(input value) 向量或者实数: 使用小写字母x等 矩阵: 使用大写字母X等 输出(output value) ...

  6. Web测试相关内容

    Q-1. Web测试的范围是什么? 答. Web测试是软件测试的名称,专注于测试基于Web的应用程序. 在进入生产环境之前,测试团队会对Web应用程序进行详尽的测试. 这有助于发现应用程序中的不同问题 ...

  7. 【转】android ViewPager,ViewFlipper,ViewFlow实现左右滑动

    转自:http://blog.csdn.net/zhouyuanjing/article/details/8290454 开篇 首页只是作为ViewPager,ViewFlipper,ViewFlow ...

  8. C#中事件的一些总结

    事件中  sender和e  事件中不同的对象 object  sender  是事件的对象 eventages e   是事件对象传递过来的参数对象 如 private button_click(O ...

  9. C#测试程序运行时间的方法

    C#测试程序运行时间的三种方法如下: (1)Datetime DateTime dtBegin = System.DateTime.Now;... DateTime dtEnnd = System.D ...

  10. BZOJ4653: [Noi2016]区间(线段树 双指针)

    题意 题目链接 Sol 按照dls的说法,一般这一类的题有两种思路,一种是枚举一个点\(M\),然后check它能否成为答案.但是对于此题来说好像不好搞 另一种思路是枚举最小的区间长度是多少,这样我们 ...