[TJOI2017]DNA——后缀数组求LCP

题目大意:

给定一个文本串和一个模式串,求文本串中有多少个连续的子串和模式串相差不超过三个字符。

思路:

算是一道后缀数组的模板题。

直接做lcp,然后遇到匹配不上的就跳,跳的次数不能超过三次。

具体地,将两个字符串连在一起,中间加一个分隔符,然后求出height,用rmq维护height数组的区间最小值即可。

/*=======================================
 * Author : ylsoi
 * Time : 2019.2.5
 * Problem : luogu3763
 * E-mail : [email protected]
 * ====================================*/
#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second
#define mk make_pair
#define pb push_back
typedef long long ll;

using namespace std;

void File(){
    freopen("luogu3763.in","r",stdin);
    freopen("luogu3763.out","w",stdout);
}

template<typename T>void read(T &_){
    _=0; T fl=1; char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')fl=-1;
    for(;isdigit(ch);ch=getchar())_=(_<<1)+(_<<3)+(ch^'0');
    _*=fl;
}

const int maxn=2e5+10;
int T;
int n,m;
char s[maxn];
int sz,sa[maxn],tp[maxn],rk[maxn],tax[maxn],height[maxn];
int st[maxn][21],Log[maxn];

void radix_sort(){
    REP(i,1,sz)tax[i]=0;
    REP(i,1,n)++tax[rk[i]];
    REP(i,1,sz)tax[i]+=tax[i-1];
    DREP(i,n,1)sa[tax[rk[tp[i]]]--]=tp[i];
}

void suffix_sort(){
    sz=26;
    REP(i,1,n)rk[i]=s[i]-'A'+1,tp[i]=i;
    radix_sort();
    for(int w=1,p=0;w<n;w<<=1){
        p=0;
        REP(i,1,w)tp[++p]=n-w+i;
        REP(i,1,n)if(sa[i]>w)tp[++p]=sa[i]-w;
        radix_sort();
        swap(rk,tp);
        rk[sa[1]]=p=1;
        REP(i,2,n)
            if(tp[sa[i-1]]==tp[sa[i]] && tp[sa[i-1]+w]==tp[sa[i]+w])rk[sa[i]]=p;
            else rk[sa[i]]=++p;
        sz=p;
        if(sz==n)break;
    }
}

void get_height(){
    int k=0;
    REP(i,1,n){
        if(k)--k;
        int j=sa[rk[i]-1];
        while(s[i+k]==s[j+k])++k;
        height[rk[i]]=k;
    }
}

void init_st(){
    REP(i,1,n)st[i][0]=height[i];
    REP(j,1,Log[n])REP(i,1,n-(1<<j)+1)
        st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}

int lcp(int x,int y){
    x=rk[x],y=rk[y];
    if(x>y)swap(x,y);
    ++x;
    int d=Log[y-x+1];
    return min(st[x][d],st[y-(1<<d)+1][d]);
}

int main(){
    File();
    REP(i,2,2e5)Log[i]=Log[i>>1]+1;
    read(T);
    while(T--){
        scanf("%s",s+1);
        m=strlen(s+1)+1;
        s[m]='Z';
        scanf("%s",s+m+1);
        n=strlen(s+1);
        suffix_sort();
        get_height();
        init_st();
        int ans=0;
        REP(i,1,m-n+m){
            int p=0,len;
            REP(j,1,4){
                len=lcp(i+p,m+1+p);
                p+=len;
                if(p==n-m){++ans; break;}
                else ++p;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ylsoi/p/10353533.html

时间: 2024-08-27 11:12:15

[TJOI2017]DNA——后缀数组求LCP的相关文章

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

题目描述 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个碱基,依然能够表现出吃藕的性状.现在研究人员想知道这个基因在DNA链S0上的位置.所以你需要统计在一个表现出吃藕性状的人的DNA序列S0上,有多少个连续子串可能是该基因,即有多少个S0的连续子串修改小于等于三个字母能够变成S. 输入输出格式 输入格式: 第一行有一个数T,表示有几组数据 每组数据第一行一个长度不超过10^5的碱基

[TJOI2017]DNA --- 后缀数组

[TJOI2017]DNA 题目描述 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S, 有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个碱基,依然能够表现出吃藕的性状. 现在研究人员想知道这个基因在DNA链\(S_{0}\)上的位置. 所以你需要统计在一个表现出吃藕性状的人的DNA序列\(S_{0}\)上,有多少个子串可能是该基因, 即有多少个\(S_{0}\)的子串修改小于等于三个字母能够变成S. 输入输出格式 输入格式: 第一行

URAL 1297. Palindrome(后缀数组求最大回文串)

题目大意:给你一串字符串,让你求出来它存在的最长连续的回文串. 解题思路:先把字符串逆序加到数组中,然后用后缀数组求解.两种方法:1,枚举排名,直接比较rank相同的字符串的位置差是不是len.如果是的话,就记录求解:2,枚举地址,求第i地址与第2*len-i+1的lcp的最大值. PS:需要注意如果多解输出靠前的字符串. 两种写法写在了一起,分别是Del,和Del1函数. 1297. Palindrome Time limit: 1.0 second Memory limit: 64 MB T

HDU 5008西安网络赛B题:后缀数组求第k小子串

思路:尼玛,这题搞了一天了,比赛的时候用了n^2的方法绝对T了,然后今天看别人代码看了一天才知道.后面感觉也挺容易的,就是没想到,之前做过SPOJ 694 705求过不同子串了,知道怎么求不同子串个数了,但是比赛的时候这个技巧竟然抛在脑后了,然后就不会了. 但是今天自己用了自己的两个后缀数组的模板(倍增和DC3)的都WA了,搞得自己真想跳楼去了!! 到现在都不知道到底是哪里错了,处理的方法和标准做法都一样,但是就是WA,然后用了别人的模板,再用自己的处理方法就过了,怀疑自己的两个模板是不是哪里错

URAL 1297. Palindrome(后缀数组 求最长回文子串)

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1297 1297. Palindrome Time limit: 1.0 second Memory limit: 64 MB The "U.S. Robots" HQ has just received a rather alarming anonymous letter. It states that the agent from the competing ?Robots

ural 1297 O(nlogn) 后缀数组求最长回文字串

把原串复制一份反过来接在原串后面,中间用没出现过的字符隔开,然后跑后缀数组,在原创枚举每一个位为回文中心(分奇偶讨论),则回文串长度相当于原串与反串对应位置的lcp,所以先用ST预处理,然后查询.复杂度O(nlogn) #include<iostream> #include<cstring> #include<set> #include<map> #include<cmath> #include<stack> #include<

POJ - 3693 Maximum repetition substring(后缀数组求重复次数最多的连续重复子串)

Description The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same consecutive substrings. For example, the repetition number of "ababab" is 3 and "ababa" is 1. Given a

hdu1403---Longest Common Substring(后缀数组求2个字符串的最长公共子串)

Problem Description Given two strings, you have to tell the length of the Longest Common Substring of them. For example: str1 = banana str2 = cianaic So the Longest Common Substring is "ana", and the length is 3. Input The input contains several

SPOJ Distinct Substrings(后缀数组求不同子串个数,好题)

DISUBSTR - Distinct Substrings no tags Given a string, we need to find the total number of its distinct substrings. Input T- number of test cases. T<=20; Each test case consists of one string, whose length is <= 1000 Output For each test case output