洛谷题目链接:[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. php性能优化--opcache

    一.OPcache是什么? OPcache通过将 PHP 脚本预编译的字节码存储到共享内存中来提升 PHP 的性能, 存储预编译字节码的好处就是 省去了每次加载和解析 PHP 脚本的开销. PHP 5 ...

  2. 硬件PCB Layout布局布线Checklist检查表(通用版)

    按部位分类 技术规范内容 1 PCB布线与布局 PCB布线与布局隔离准则:强弱电流隔离.大小电压隔离,高低频率隔离.输入输出隔离.数字模拟隔离.输入输出隔离,分界标准为相差一个数量级.隔离方法包括:空 ...

  3. 自测之Lesson7:设备文件操作

    题目:请编写一个输入密码(不回显)的程序,要求通过设置终端来完成. 完成代码: #include <stdio.h> #include <unistd.h> #include ...

  4. PHP连接Redis操作函数

    phpredis是php的一个扩展,效率是相当高有链表排序功能,对创建内存级的模块业务关系 很有用;以下是redis官方提供的命令使用技巧: 下载地址如下: https://github.com/ow ...

  5. setsockopt 设置socket 详细用法

    1.closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:BOOL bReuseaddr=TRUE;setsockopt(s,SOL_SOCKET ,SO ...

  6. 基本数据类型(int,bool,str)

    目录: 1.int        数字类型 2.bool      布尔值 3.str    字符串类型 一.整型(int) 在python3中所有的整数都是int类型.但在python2中如果数据量 ...

  7. vs code 自动补全效果不理想的问题

    之前一直用webstorm,最近换换口味,改用了VS Code,发现VS Code 智能提示得到的都不是我想要的 就比如  ! + tab ,HTML结构都出不来.经过一番搜索,发现是 VS Code ...

  8. BZOJ4709 JSOI2011柠檬(动态规划)

    首先要冷静下来发现这仅仅是在划分区间.显然若有相邻的数字相同应当划分在同一区间.还有一个显然的性质是区间的两端点应该相同且选择的就是端点的数.瞬间暴力dp就变成常数极小100002了.可以继续斜率优化 ...

  9. Docker-端口映射

    Docker-端口映射 Docker端口映射 docker容器在启动的时候,如果不指定端口映射参数,在容器外部是无法通过网络来访问容器内的网络应用和服务的. 亦可使用Dockerfile文件中的EXP ...

  10. HDU5696:区间的价值——题解

    http://acm.hdu.edu.cn/showproblem.php?pid=5696 题面是中文的我就不粘贴过来了…… ———————————————————————— 这题垃圾题!!神tm卡 ...