zoukankan      html  css  js  c++  java
  • [BZOJ4892][TJOI2017]DNA

    bzoj
    luogu

    题意

    给你一个原串和一个模式串,问你这个模式串在原串中出现了几次。
    模式串在原串中出现一次定义为按位匹配时不匹配的字符数不超过(3)

    sol

    实际上一次匹配就是求至多(4)(lcp)的过程。
    从第一位开始匹配,如果不同就跳过一次(跳过次数不能超过(3)),否则匹配长度+=当前两个位置的(lcp)
    所以用(SA)跑就行了。

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int N = 2e5+5;
    int n,a[N],t[N],x[N],y[N],SA[N],Rank[N],Height[20][N],lg[N];
    char s[N];
    bool cmp(int i,int j,int k){return y[i]==y[j]&&y[i+k]==y[j+k];}
    void getSA(){
    	int m=30;
    	for (int i=0;i<=m;++i) t[i]=0;
    	for (int i=1;i<=n;++i) ++t[x[i]=a[i]];
    	for (int i=1;i<=m;++i) t[i]+=t[i-1];
    	for (int i=n;i>=1;--i) SA[t[x[i]]--]=i;
    	for (int k=1;k<=n;k<<=1){
    		int p=0;
    		for (int i=0;i<=m;++i) y[i]=0;
    		for (int i=n-k+1;i<=n;++i) y[++p]=i;
    		for (int i=1;i<=n;++i) if (SA[i]>k) y[++p]=SA[i]-k;
    		for (int i=0;i<=m;++i) t[i]=0;
    		for (int i=1;i<=n;++i) ++t[x[y[i]]];
    		for (int i=1;i<=m;++i) t[i]+=t[i-1];
    		for (int i=n;i>=1;--i) SA[t[x[y[i]]]--]=y[i];
    		swap(x,y);x[SA[1]]=p=1;
    		for (int i=2;i<=n;++i) x[SA[i]]=cmp(SA[i],SA[i-1],k)?p:++p;
    		if (p>=n) break;m=p;
    	}
    	for (int i=1;i<=n;++i) Rank[SA[i]]=i;
    	for (int i=1,j=0;i<=n;++i){
    		if (j) --j;
    		while (a[i+j]==a[SA[Rank[i]-1]+j]) ++j;
    		Height[0][Rank[i]]=j;
    	}
    	for (int i=2;i<=n;++i) lg[i]=lg[i>>1]+1;
    	for (int j=1;j<=lg[n];++j)
    		for (int i=1;i+(1<<j)-1<=n;++i)
    			Height[j][i]=min(Height[j-1][i],Height[j-1][i+(1<<j-1)]);
    }
    int lcp(int i,int j){
    	i=Rank[i];j=Rank[j];if (i>j) swap(i,j);
    	if (i==j) return (int)1e9;++i;
    	int k=lg[j-i+1];
    	return min(Height[k][i],Height[k][j-(1<<k)+1]);
    }
    int main(){
    	int T;scanf("%d",&T);
    	while (T--){
    //		memset(s,0,sizeof(s));
    		scanf("%s",s+1);n=strlen(s+1);
    		for (int i=1;i<=n;++i) a[i]=s[i]-'A'+1;
    		int n1=n;a[++n]=27;
    //		memset(s,0,sizeof(s));
    		scanf("%s",s+1);int m=strlen(s+1);
    		for (int i=1;i<=m;++i) a[++n]=s[i]-'A'+1;
    		getSA();int ans=0;
    		for (int i=1;i<=n1-m+1;++i){
    			int tim=0;
    			for (int j=1;j<=m&&tim<=3;){
    				if (a[i+j-1]!=a[n1+1+j]) ++tim,++j;
    				else j+=lcp(i+j-1,n1+1+j);
    			}
    			if (tim<=3) ++ans;
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Entity Framework Code First 模式-建立一对一联系
    Entity Framework Code First 模式-建立一对多联系
    sqllocaldb
    NuGet 命令行使用EntityFrameWork
    c# 中反射里的invoke方法的参数
    在js中使用Razor
    一个页面上调用多个setInterval失效解决办法(使用于同一时间间隔)
    Echart使用过的属性总结
    VS注释与取消注释快捷键
    hibernate的强转类型
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9092503.html
Copyright © 2011-2022 走看看