后缀数组

先开始nc了,觉得自动机做法是指数级的,就写了个后缀数组

具体方法是暴力,枚举起点,然后用lcp向后暴力匹配,如果失配就减少一次,我们一共有3次机会,这样每次匹配复杂度是O(1)的,所以总复杂度是O(nlogn+n),然后t掉了,交了发别人代码,bzoj怎么那么慢,洛谷跑的飞快。调了很长时间发现sa板子写错了,明明是粘过来的。。。

后缀自动机就是在自动机上匹配,如果不匹配可以随便走,每次匹配完统计就行了

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + ;
int n, m, k, len, pos, ans;
char s[N], t[N];
int p[N], a[N], b[N], rank[N], lcp[N], sa[N], mn[N][], mp[], Log[N], tmp[N];
void radix(int *s, int *a, int *b, int n, int m)
{
int count[N]; memset(count, , sizeof(count));
for(int i = ; i <= n; ++i) ++count[s[a[i]]];
for(int i = ; i <= m; ++i) count[i] += count[i - ];
for(int i = n; i; --i) b[count[s[a[i]]]--] = a[i];
}
void Sa(int *s, int n)
{
for(int i = ; i <= n; ++i) rank[i] = i;
radix(s, rank, sa, n, );
rank[sa[]] = ;
for(int i = ; i <= n; ++i) rank[sa[i]] = rank[sa[i - ]] + (s[sa[i]] != s[sa[i - ]]);
for(int k = ; k <= n; k <<= )
{
for(int i = ; i <= n; ++i)
{
a[i] = rank[i];
b[i] = i + k <= n ? rank[i + k] : ;
sa[i] = i;
}
radix(b, sa, rank, n, n);
radix(a, rank, sa, n, n);
rank[sa[]] = ;
for(int i = ; i <= n; ++i) rank[sa[i]] = rank[sa[i - ]] + (a[sa[i]] != a[sa[i - ]] || b[sa[i]] != b[sa[i - ]]);
}
}
void Lcp(int *s, int n)
{
int h = ;
for(int i = ; i <= n; ++i) rank[sa[i]] = i;
for(int i = ; i <= n; ++i)
{
int j = sa[rank[i] - ];
if(rank[i] <= ) continue;
if(h > ) --h;
for(; i + h <= n && j + h <= n; ++h) if(s[i + h] != s[j + h]) break;
mn[rank[i] - ][] = h;
}
for(int j = ; j <= ; ++j)
for(int i = ; i + ( << j) - <= n; ++i)
mn[i][j] = min(mn[i][j - ], mn[i + ( << (j - ))][j - ]);
}
int query(int l, int r)
{
l = rank[l];
r = rank[r];
if(l > r) swap(l, r);
--r;
int x = Log[r - l + ];
return min(mn[l][x], mn[r - ( << x) + ][x]);
}
int main()
{
int T;
scanf("%d", &T);
mp['A'] = ;
mp['G'] = ;
mp['C'] = ;
mp['T'] = ;
for(int i = ; i < N; ++i) Log[i] = Log[i >> ] + ;
while(T--)
{
ans = ;
scanf("%s%s", s + , t + );
len = ;
n = strlen(s + );
m = strlen(t + );
for(int i = ; i <= n; ++i) p[++len] = mp[s[i]];
p[++len] = ;
pos = len + ;
for(int i = ; i <= m; ++i) p[++len] = mp[t[i]];
Sa(p, len);
Lcp(p, len);
for(int i = ; i <= n - m + ; ++i)
{
int tmp = m, cnt = , p1 = i, p2 = pos;
while(tmp > )
{
int x = query(p1, p2);
tmp -= x;
p1 += x;
p2 += x;
if(tmp <= ) break;
while(cnt >= && p[p1] != p[p2] && p1 <= n && p2 <= len)
{
++p1;
++p2;
--tmp;
--cnt;
}
if(cnt < || p2 > len || p1 > n) break;
}
if(cnt >= && tmp <= ) ++ans;
}
printf("%d\n", ans);
}
return ;
}

bzoj4892的更多相关文章

  1. bzoj4892 [TJOI2017]DNA

    bzoj4892 [TJOI2017]DNA 给定一个匹配串和一个模式串,求模式串有多少个连续子串能够修改不超过 \(3\) 个字符变成匹配串 \(len\leq10^5\) hash 枚举子串左端点 ...

  2. BZOJ4892 Tjoi2017dna(后缀数组)

    对每个子串暴力匹配至失配三次即可.可以用SA查lcp.然而在bzoj上被卡常了.当然也可以二分+哈希或者SAM甚至FFT. #include<iostream> #include<c ...

  3. 【BZOJ4892】DNA(后缀数组)

    [BZOJ4892]DNA(后缀数组) 题面 BZOJ 洛谷 题解 看到这道题目,我第一反应是\(FFT\)??? 然后大力码出了一个\(FFT\) 就像这样 #include<iostream ...

  4. BZOJ4892:[TJOI2017]dna(hash)

    Description 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个碱基,依然能够表 ...

  5. [BZOJ4892][TJOI2017]DNA(后缀数组)

    题目描述 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个碱基,依然能够表现出吃藕的性状 ...

  6. 字符串Hash/树Hash学习笔记

    哈希 Tags:字符串 作业部落 评论地址 一.概述 百度百科: 散列表(Hash table/哈希表),是根据关键码值(Key value)而直接进行访问的数据结构. 哈希表常用于比较两个字符串是否 ...

  7. FFT_应用和例题

    卷积 现有两个定义在 N 上的函数 \(f(n),g(n)\),定义 \(f\) 和 \(g\) 的卷积(convolution)为 \(f \otimes g\) \[ (f \otimes g)( ...

随机推荐

  1. android页面间传递对象

    android传递对象有两种方式: 一种是Serializable和Parcelable 对于第一种方式: import java.io.Serializable; public class Shop ...

  2. Spring.net1.3.1+Nhibernate3.0+Mysql/Access/SqlServer/Oracel/SQlite

    详情请看我的博文:http://www.ruisoftcn.com/blog/article.asp?id=999

  3. Qt5的插件机制(6)--开发Qt插件时几个重要的宏

    怎样开发Qt插件,能够在Qt Assistant 中搜索"Qt Plugins"或"How to Create Qt Plugins",看看那篇manual中的 ...

  4. [Android5 系列—] 1. 构建一个简单的用户界面

    前言 安卓应用的用户界面是构建在View 和ViewGroup 这两个物件的层级之上的. View 就是一般的UI组件.像button,输入框等. viewGroup 是一些不可见的view的容器,用 ...

  5. 设置Ubuntu 16.04 LTS的Unity启动器的位置命令

    将Ubuntu 16.04 LTS的Unity启动器移动到桌面底部命令:gsettings set com.canonical.Unity.Launcher launcher-position Bot ...

  6. 文件I/O相关函数

    open()和openat()函数: #include <fcntl.h> // 成功返回文件描述符,出错返回-1 int open(const char *path, int oflag ...

  7. g++ 6.4编译opencv-2.4.10报错记录

      fetch公司的项目进行编译,此项目依赖opencv库.由于本人一直比较偏爱fedora,但也因此给我带来了许多"乐趣"(麻烦).fedora一直走得比较前沿,g++ 6.3了 ...

  8. linux下解压命令大全(转载)

    转自:http://www.cnblogs.com/eoiioe/archive/2008/09/20/1294681.html .tar 解包:tar xvf FileName.tar打包:tar ...

  9. 顺序容器vector,deque,list的选用规则

    前言 常见的顺序容器主要有三种 - vector,deque,list.它们实现的功能相差不大,那么实际开发中该如何进行选择呢?本文将为你解答这个问题. 分析 由于这三种容器实现的数据结构原型不同(v ...

  10. 【转】IDA 调试 Android

    最近都在学一些反编译安卓相关的东西,其实网上有很多教程关于用 IDA 调试 Android 的过程,主要记录一下我遇到的坑 首先 Android手机要是root过的 还要注意的一点是apk中的 And ...