洛谷题目链接:[TJOI2017]DNA

题目描述

加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个碱基,依然能够表现出吃藕的性状。现在研究人员想知道这个基因在DNA链S0上的位置。所以你需要统计在一个表现出吃藕性状的人的DNA序列S0上,有多少个连续子串可能是该基因,即有多少个S0的连续子串修改小于等于三个字母能够变成S。

输入输出格式

输入格式:

第一行有一个数T,表示有几组数据 每组数据第一行一个长度不超过10^5的碱基序列S0

每组数据第二行一个长度不超过10^5的吃藕基因序列S

输出格式:

共T行,第i行表示第i组数据中,在S0中有多少个与S等长的连续子串可能是表现吃藕性状的碱基序列

输入输出样例

输入样例#1:

1

ATCGCCCTA

CTTCA

输出样例#1:

2

说明

对于20%的数据,S0,S的长度不超过10^4

对于100%的数据,S0,S的长度不超过10^5,0<T<=10

题意: 问字符串\(s\)中有多少个长度为\(n0\)的连续的子串与字符串\(s0\)的不同在\(3\)个以内.


题解: 考虑在\(s\)中枚举字符串的起点,如果当前枚举到的位置与\(s0\)中的对应位置相同的话,就向后延伸它们的\(lcp\)的长度.如果不相同,就计数器加\(1\),继续向后枚举,如果枚举长度超过\(s0\)的长度\(n0\)了,说明这次枚举的起点合法.

求\(lcp\)的过程可以用哈希预处理二分长度的方法在\(O(logn)\)的时间内求出,也可以后缀数组预处理在\(O(1)\)的时间内求出.

用后缀数组预处理主要是用到了这个性质:\(lcp(suffix(sa[i]),suffix(sa[j]))=min\{height[k]\}(i<j,k\in[i,j])\)

这样就可以在求出\(height\)数组的情况下用倍增预处理出一段连续排名的\(height\)数组的最小值,然后\(O(1)\)查询了.

#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 2e5+5; int T, n, n0, m, sa[N], rk[N], sec[N], buk[N], height[N], f[25][N], Log[N], ans = 0;
char s[N], s0[N]; void rsort(){
for(int i = 0; i <= m; i++) buk[i] = 0;
for(int i = 1; i <= n; i++) buk[rk[i]]++;
for(int i = 1; i <= m; i++) buk[i] += buk[i-1];
for(int i = n; i >= 1; i--) sa[buk[rk[sec[i]]]--] = sec[i];
} void SuffixArray(){
for(int i = 1; i <= n; i++) rk[i] = s[i], sec[i] = i;
m = 260; rsort(); int num = 0;
for(int l = 1; l <= n && num < n; l <<= 1){
num = 0;
for(int i = 1; i <= l; i++) sec[++num] = n-l+i;
for(int i = 1; i <= n; i++) if(sa[i] > l) sec[++num] = sa[i]-l;
rsort(); swap(rk, sec), rk[sa[1]] = num = 1;
for(int i = 2; i <= n; i++)
rk[sa[i]] = (sec[sa[i]] == sec[sa[i-1]] && sec[sa[i]+l] == sec[sa[i-1]+l]) ? num : ++num;
m = num;
}
} void get_height(){
int j, k = 0;
for(int i = 1; i <= n; i++){
if(k) k--;
j = sa[rk[i]-1];
while(s[i+k] == s[j+k]) k++;
height[rk[i]] = k;
}
} void init(){
for(int i = 1; i <= n; i++) f[0][i] = height[i];
for(int j = 1; j <= 20; j++)
for(int i = 1; i+(1<<j)-1 <= n+n0; i++)
f[j][i] = min(f[j-1][i], f[j-1][i+(1<<(j-1))]);
} int lcp(int x, int y){
x = rk[x], y = rk[y]; if(x > y) swap(x, y);
x++;int lg = Log[y-x+1];
return min(f[lg][x], f[lg][y-(1<<lg)+1]);
} void clear(){
memset(f, 0x3f, sizeof(f));
ans = 0;
} int main(){
cin >> T; Log[0] = -1;
for(int i = 1; i <= 200000; i++) Log[i] = Log[i>>1]+1;
while(T--){
cin >> (s+1) >> (s0+1), n = strlen(s+1), n0 = strlen(s0+1);
for(int i = 1; i <= n0; i++) s[i+n] = s0[i]; n += n0;
SuffixArray(), get_height(), init();
for(int i = 1; i <= n-n0*2+1; i++){
int cnt = 0;
for(int j = 1; j <= n0 && cnt <= 3; j++){
if(s[i+j-1] != s[n-n0+j]) cnt++;
else j += lcp(i+j-1, n-n0+j)-1;
}
if(cnt <= 3) ans++;
}
cout << ans << endl;
clear();
}
return 0;
}

[洛谷P3763] [TJOI2017]DNA的更多相关文章

  1. 洛谷P3763 [Tjoi2017]DNA 【后缀数组】

    题目链接 洛谷P3763 题解 后缀数组裸题 在BZOJ被卡常到哭QAQ #include<algorithm> #include<iostream> #include< ...

  2. 洛谷P3763 [TJOI2017]DNA(后缀数组 RMQ)

    题意 题目链接 Sol 这题打死我也不会想到后缀数组的,应该会全程想AC自动机之类的吧 但知道这题能用后缀数组做之后应该就不是那么难了 首先把\(S\)和\(S0\)拼到一起跑,求出Height数组 ...

  3. 洛谷P3763 [TJOI2017]DNA(后缀自动机)

    传送门 好像用SAM写的很少诶…… 其实我一开始也没想到要用SAM的……主要是没有想到找的时候可以dfs…… 首先建一个SAM,然后跑一遍dfs,枚举一下下一位,如果相同直接继续,否则就花费一次次数来 ...

  4. [洛谷P3761] [TJOI2017]城市

    洛谷题目链接:[TJOI2017]城市 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速 ...

  5. 洛谷P3759 [TJOI2017]不勤劳的图书管理员 【树状数组套主席树】

    题目链接 洛谷P3759 题解 树状数组套主席树板题 #include<algorithm> #include<iostream> #include<cstring> ...

  6. P3763 [TJOI2017]DNA

    链接:https://www.luogu.org/problemnew/show/P3763 题解: 挺水的一题后缀数组 枚举每一个开头用后缀数组判断能否在3次内匹配完

  7. 洛谷P3760 - [TJOI2017]异或和

    Portal Description 给出一个\(n(n\leq10^5)\)的序列\(\{a_n\}(\Sigma a_i\leq10^6)\),求该数列所有连续和的异或和. Solution 线段 ...

  8. 洛谷P3759 - [TJOI2017]不勤劳的图书管理员

    Portal Description 给出一个\(1..n(n\leq5\times10^4)\)的排列\(\{a_n\}\)和数列\(\{w_n\}(w_i\leq10^5)\),进行\(m(m\l ...

  9. 洛谷P3758 - [TJOI2017]可乐

    Portal Description 给出一张\(n(n\leq30)\)个点\(m(m\leq100)\)条边的无向图.初始时有一个可乐机器人在点\(1\),这个机器人每秒会做出以下三种行为之一:原 ...

随机推荐

  1. CentOS6 安装VNCserver

    1.下载vncserver yum install tigervnc tigervnc-server -y 2.配置 vncserver vi /etc/sysconfig/vncserver 在文件 ...

  2. Java学习个人备忘录之异常

    概述 异常:是在运行时期发生的不正常情况. 在java中用类的形式对不正常情况进行了描述和封装对象. 描述不正常的情况的类,就称为异常类. 以前正常流程代码和问题处理代码相结合,现在将正常流程代码和问 ...

  3. 20145214实验一 Java开发环境的熟悉

    20145214实验一 Java开发环境的熟悉 使用JDK编译.运行简单的java程序 命令行下程序开发 在命令行下建立20145214实验目录,进入该目录后创建exp1目录. 把代码保存到exp1目 ...

  4. Alpha冲刺——第三天

    Alpha第三天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...

  5. 原生js操作Dom节点:CRUD

    知识点,依然会遗忘.我在思考到底是什么原因.想到研究生考试准备的那段岁月,想到知识体系的建立,知识体系分为正向知识体系和逆向知识体系:正向知识体系可以理解为教科书目录,逆向知识体系可以理解考试真题. ...

  6. 【Python】ORM框架SQLAlchemy的使用

    ORM和SQLAlchemy简介 对象关系映射(Object Relational Mapping,简称ORM),简单的来说,ORM是将数据库中的表与面向对象语言中的类建立了一种对应的关系.然后我们操 ...

  7. 威锋网(Weiphone) BBS排序插件

    body,td,p { // 这对大括号里描述网页的背景 margin-left:40px; margin-right:40px; font-size: 10pt; } div.vim { width ...

  8. bzoj4555-求和

    题目 \(S(i,j)\)表示第二类斯特林数,求: \[ f(n)=\sum _{i=0}^n\sum _{j=0}^iS(i,j)*2^j*j! \] 分析 公式推理很简单,关键是用到了第二类斯特林 ...

  9. JS内存空间详细图解

    JS内存空间详细图解 变量对象与堆内存 var a = 20; var b = 'abc'; var c = true; var d = { m: 20 } 因为JavaScript具有自动垃圾回收机 ...

  10. STL使用记录

    1,map 对map实在不熟...赶紧记录一下用法吧. 后来再发现新的用法再补充吧 定义: map<int, int> m; 其中的int可以为自定义的任何类型. m[key值类型的变量] ...