Luogu3763 TJOI2017 DNA NTT/SA
两种做法:
①SA
将两个串拼在一次建立后缀数组,把\(height\)数组求出来,然后对于\(S\)中每一个长度为\(T\)的串和\(T\)暴力匹配,每一次找到最长的\(LCP\)匹配,如果失配次数\(>3\)就直接退出。总复杂度\(O(T(NlogN+4N))\)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
//This code is written by Itst
using namespace std;
const int MAXN = 2e5 + 7;
char s[MAXN];
int sa[MAXN] , rk[MAXN << 1] , tp[MAXN << 1] , pot[MAXN] , h[MAXN] , ST[19][MAXN];
int ls , L , maxN;
void sort(int p){
memset(pot , 0 , sizeof(int) * (maxN + 1));
for(int i = 1 ; i <= L ; ++i)
++pot[rk[i]];
for(int i = 1 ; i <= maxN ; ++i)
pot[i] += pot[i - 1];
for(int i = 1 ; i <= L ; ++i)
sa[++pot[rk[tp[i]] - 1]] = tp[i];
memcpy(tp , rk , sizeof(int) * (L + 1));
for(int i = 1 ; i <= L ; ++i)
rk[sa[i]] = rk[sa[i - 1]] + (tp[sa[i]] != tp[sa[i - 1]] || tp[sa[i] + p] != tp[sa[i - 1] + p]);
maxN = rk[sa[L]];
}
void init(){
maxN = 26;
for(int i = 1 ; i <= L ; ++i)
rk[tp[i] = i] = s[i] - 'A' + 1;
sort(0);
for(int i = 1 ; maxN != L ; i <<= 1){
int cnt = 0;
for(int j = 1 ; j <= i ; ++j)
tp[++cnt] = L - i + j;
for(int j = 1 ; j <= L ; ++j)
if(sa[j] > i)
tp[++cnt] = sa[j] - i;
sort(i);
}
for(int i = 1 ; i <= L ; ++i){
if(rk[i] == 1)
continue;
int t = rk[i];
h[t] = max(0 , h[rk[i - 1]] - 1);
while(s[sa[t] + h[t]] == s[sa[t - 1] + h[t]])
++h[t];
}
}
void init_ST(){
for(int i = 2 ; i <= L ; ++i)
ST[0][i] = h[i];
for(int i = 1 ; (1 << i) + 1 <= L ; ++i)
for(int j = 2 ; j + (1 << i) - 1 <= L ; ++j)
ST[i][j] = min(ST[i - 1][j] , ST[i - 1][j + (1 << (i - 1))]);
}
inline int qST(int x , int y){
if(x > y)
swap(x , y);
int t = log2(y - x);
return min(ST[t][x + 1] , ST[t][y - (1 << t) + 1]);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
int T;
for(scanf("%d" , &T) ; T ; --T){
scanf("%s" , s + 1);
ls = strlen(s + 1);
scanf("%s" , s + ls + 1);
L = strlen(s + 1);
init();
init_ST();
int ans = 0;
for(int i = 1 ; i <= ls - (L - ls) + 1 ; ++i){
int posS = i , posT = ls + 1 , cnt = 0;
while(cnt <= 3 && posT <= L){
int t = qST(rk[posS] , rk[posT]);
posT += t;
posS += t;
if(posT > L)
break;
++cnt;
++posS;
++posT;
}
if(cnt <= 3)
++ans;
}
cout << ans << endl;
}
return 0;
}
②NTT
将模板串翻转,对于\(AGCT\)每一个做一次\(NTT\):如果匹配串第\(i\)位为当前字符则\(a_i=1\)否则\(a_i = 0\),模板串同理。然后NTT得到两个数组的卷积,就可得到匹配串每个位置的子串与模板串之间匹配字符为\(A\)的匹配次数。复杂度\(O(4TNlogN)\)
#include<iostream>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
//This code is written by Itst
using namespace std;
const int G = 3 , MOD = 998244353 , INV = 332748118 , MAXN = (1 << 18) + 7;
const char exp[] = "AGCT";
int num[MAXN] , dir[MAXN] , sum[MAXN] , A[MAXN] , B[MAXN];
int need , inv_need , lS , lT;
char s[MAXN] , t[MAXN];
inline int poww(long long a , int b){
int times = 1;
while(b){
if(b & 1)
times = times * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return times;
}
void init(int x){
need = 1;
while(need < x)
need <<= 1;
inv_need = poww(need , MOD - 2);
for(int i = 1 ; i <= need ; ++i)
dir[i] = (dir[i >> 1] >> 1) | (i & 1 ? need >> 1 : 0);
}
void NTT(int *arr , int tp){
for(int i = 1 ; i < need ; ++i)
if(i < dir[i])
arr[i] ^= arr[dir[i]] ^= arr[i] ^= arr[dir[i]];
for(int i = 1 ; i < need ; i <<= 1){
int wn = poww(tp == 1 ? G : INV , (MOD - 1) / i / 2);
for(int j = 0 ; j < need ; j += i << 1){
long long w = 1;
for(int k = 0 ; k < i ; ++k , w = w * wn % MOD){
int x = arr[j + k] , y = arr[i + j + k] * w % MOD;
arr[j + k] = x + y >= MOD ? x + y - MOD : x + y;
arr[i + j + k] = x < y ? x - y + MOD : x - y;
}
}
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
int T;
for(scanf("%d" , &T) ; T ; --T){
scanf("%s %s" , s + 1 , t + 1);
lS = strlen(s + 1);
lT = strlen(t + 1);
init(lS + lT);
memset(sum , 0 , sizeof(int) * need);
reverse(t + 1 , t + lT + 1);
for(int j = 0 ; j < 4 ; ++j){
memset(A , 0 , sizeof(int) * need);
memset(B , 0 , sizeof(int) * need);
char c = exp[j];
for(int i = 1 ; i <= lS ; ++i)
A[i] = s[i] == c;
for(int i = 1 ; i <= lT ; ++i)
B[i] = t[i] == c;
NTT(A , 1); NTT(B , 1);
for(int i = 0 ; i < need ; ++i)
A[i] = 1ll * A[i] * B[i] % MOD;
NTT(A , -1);
for(int i = lT + 1 ; i <= lS + 1 ; ++i)
sum[i] = sum[i] + A[i] >= MOD ? sum[i] + A[i] - MOD : sum[i] + A[i];
}
int cnt = 0;
for(int i = lT + 1 ; i <= lS + 1 ; ++i)
cnt += 1ll * sum[i] * inv_need % MOD >= lT - 3;
cout << cnt << endl;
}
return 0;
}
Luogu3763 TJOI2017 DNA NTT/SA的更多相关文章
- [洛谷P3763] [TJOI2017]DNA
洛谷题目链接:[TJOI2017]DNA 题目描述 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其 ...
- [TJOI2017] DNA - 后缀数组,稀疏表
[TJOI2017] DNA Description 求模式串与主串的匹配次数,容错不超过三个字符. Solution 枚举每个开始位置,进行暴力匹配,直到失配次数用光或者匹配成功.考虑到容错量很小, ...
- bzoj4892 [TJOI2017]DNA
bzoj4892 [TJOI2017]DNA 给定一个匹配串和一个模式串,求模式串有多少个连续子串能够修改不超过 \(3\) 个字符变成匹配串 \(len\leq10^5\) hash 枚举子串左端点 ...
- [TJOI2017]DNA --- 后缀数组
[TJOI2017]DNA 题目描述 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S, 有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个 ...
- BZOJ.4892.[TJOI2017]DNA(后缀自动机/后缀数组)
题目链接 \(Description\) 给出两个串\(S,T\),求\(T\)在\(S\)中出现了多少次.出现是指.可以有\(3\)次(\(3\)个字符)不匹配(修改使其匹配). \(Solutio ...
- [BZOJ4892][TJOI2017]DNA(后缀数组)
题目描述 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个碱基,依然能够表现出吃藕的性状 ...
- 洛谷3763:[TJOI2017]DNA——题解
https://www.luogu.org/problemnew/show/P3763 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是 ...
- BZOJ4892:[TJOI2017]dna(hash)
Description 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个碱基,依然能够表 ...
- 洛谷P3763 [TJOI2017]DNA(后缀数组 RMQ)
题意 题目链接 Sol 这题打死我也不会想到后缀数组的,应该会全程想AC自动机之类的吧 但知道这题能用后缀数组做之后应该就不是那么难了 首先把\(S\)和\(S0\)拼到一起跑,求出Height数组 ...
随机推荐
- 【读书笔记】iOS-配件
如果你想用External Accessory框架开发第三方硬件设备,你需要考虑成为Made for iPhone(MFI)授权项目的成员. 得到授权的开发者可以获取技术资料,硬件设备以及技术支持,以 ...
- JS性能优化 之 文档片段 createDocumentFragment
我们用原生JS进行开发时,经常会用到两种更新DOM节点的方法:innerHTML 和 appendChild() .其中 innerHTML 会完全替换掉原先的节点内容,如果我们是想向元素追加子节点的 ...
- python自动化开发-5
列表生成式 生成器 迭代器 列表生成式 举个例子 列表[0, 1, 2, 3, 4, 5, 6],要求把列表里的每个值加1,如何实现呢? L=[0, 1, 2, 3, 4, 5, 6] a={i+ ...
- MQTT详解以及在IoT中的应用
MQTT定义: MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分.该协议支持所有平台, ...
- IDEA错误:Failed to start end point associated with ProtocolHandler [http-nio-9999] java.net.BindException: Address already in use: bind
日志显示进程端口已被占用,首先需要的是查询什么进程占用了当前的9999端口. 1.win+R输入cmd进入命令界面: 2.输入命令 netstat -ano|findstr "端口号&qu ...
- Android View体系(八)从源码解析View的layout和draw流程
前言 上一篇文章我们讲了View的measure的流程,接下来我们讲下View的layout和draw流程,如果你理解了View的measure的流程,那这篇文章自然就不在话下了. 1.View的la ...
- 转 fiddler常见的应用场景
fiddler常见的应用场景 在移动互联网时代,作为软件测试工程师,fiddler绝对是值得掌握并添加进技术栈里的工具之一. 那么,fiddler在日常的测试工作中,一般都有哪些常见的应用场景呢? ...
- sass @function,@for,@mixin 的应用
项目前提: 不同的汽车显示不同的图片,一共9种汽车:每种汽车显示不同状态的图片,一共6种状态,所以一共会有54张图片 后台接口返回汽车种类分别为:1-9,汽车状态分别为:0-5 项目需求: 根据后台返 ...
- python第六十八天--第十二周作业
主题: 需求: 用户角色,讲师\学员, 用户登陆后根据角色不同,能做的事情不同,分别如下讲师视图 管理班级,可创建班级,根据学员qq号把学员加入班级 可创建指定班级的上课纪录,注意一节上课纪录对应多条 ...
- tkinter学习系列(二)之窗口的设置
目录 (一)窗体的最小框架 1.说明: 2.源代码: 3.实现效果: (二)窗体的基本设置 1.说明: 2.完整代码: 3.实现效果: (三)窗体的外形设置 1.说明: 2.完整代码: 3.实现效果: ...