• Jzoj3351 神牛养成计划2


    前文再续,书接上回,话说神牛yxr成功培育出神牛细胞,可最终培育出来的生物体却让他大失所望……

    后来,他从某GD女神 牛处知道,原来他培育的细胞发生了基因突变,原先决定神牛特征的基因序列都被破坏了,神牛yxr很生气,但他知道基因突变有低频性,说不定还有一些优秀基因没有突变,那么他就可以用限制性核酸内切酶把它们切出来,然后再构建基因表达载体什么的,后面的你懂的。

    神牛yxr现在知道了N个细胞的DNA序列,它们是若干个由小写字母组成的字符串(为什么不是ATCG,因为突变得太厉害)。一个优秀基因是两个字符串s1和s2,当且仅当s1是某序列的前缀同时s2是这个序列的后缀时,神牛yxr认为这个序列拥有这个优秀基因。

    现在神牛yxr知道了M个优秀基因的s1和s2,他想知道对于给定的优秀基因,有多少个细胞的DNA序列拥有它。


    题意就是求有多少个串前缀是s1后缀是s2

    用SAM不太方便,hash也不太好搞

    那么我们考虑一下用Trie

    我们先将所有的DNA序列插入到Trie中

    那么显然,一次查询我们可以视为查Trie上一个子树有多少串满足后缀是s2

    考虑对每个串按照在Trie中的顺序标号,再将每个串反过来插到另一个trie上面

    显然拥有同一个前缀的串,编号是连续的,拥有同一个后缀的串在一个子树中

    那么问题就变成了,在第二个Trie的一个子树中查找编号在[l,r]的方案个数

    可以用一个dfs序加上主席树完成

    (p.s这种数据结构题还是比较好打的毕竟思路清晰不易错)

    #pragma GCC optimize("O3")
    #pragma G++ optimize("O3")
    #include<bitset>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define N 2010
    #define M 2000010
    #define mid (l+r>>1)
    using namespace std;
    struct tree{ int l,r,s; } s[N<<4];
    int n,m,cnt=0,tot=0,l[M<<1],r[M<<1],son[M<<1][26],c[M<<1];
    int sa[N],rk[N],clk=0,r1,r2,wl[M<<1],wr[M<<1],d[M],rt[M],L[N]; char str[M+N],q[M];
    inline char* insert(char* s,int x,int p){
    	for(;*s;++s)
    		x=son[x][*s-'a']?son[x][*s-'a']:son[x][*s-'a']=++cnt;
    	c[x]=p; return --s;
    }
    inline void dfs(int x){
    	if(c[x]){
    		sa[++clk]=c[x]; rk[c[x]]=clk; l[x]=r[x]=clk;
    	} else l[x]=n;
    	for(int j=0;j<26;++j)
    		if(son[x][j]){
    			dfs(son[x][j]);
    			l[x]=min(l[x],l[son[x][j]]);
    			r[x]=max(r[x],r[son[x][j]]);
    		}
    }
    inline void rinsert(char* s,int x,int p){
    	for(;*s;--s)
    		x=son[x][*s-'a']?son[x][*s-'a']:son[x][*s-'a']=++cnt;
    	c[x]=p;
    }
    inline void dfs2(int x){
    	wl[x]=++clk; d[clk]=c[x];
    	for(int j=0;j<26;++j)
    		if(son[x][j]) dfs2(son[x][j]);
    	wr[x]=clk;
    }
    inline void ins(int l,int r,int r1,int& r2,int k){
    	r2=++tot; s[r2].s=s[r1].s+1;
    	if(l==r) return;
    	if(k<=mid){ s[r2].r=s[r1].r; ins(l,mid,s[r1].l,s[r2].l,k); }
    		else{ s[r2].l=s[r1].l; ins(mid+1,r,s[r1].r,s[r2].r,k); }
    }
    inline int g(int x,char* s,int lst){
    	for(;*s;++s)
    		x=son[x][(*s-'a'+lst)%26];
    	return x;
    }
    inline int query(int l,int r,int r1,int r2,int k){
    	if(l==r) return 0;
    	if(k<=mid) return query(l,mid,s[r1].l,s[r2].l,k);
    	else return s[s[r2].l].s-s[s[r1].l].s+query(mid+1,r,s[r1].r,s[r2].r,k);
    }
    int main(){
    	scanf("%d",&n); r1=++cnt; r2=++cnt;
    	for(int i=1,x;i<=n;++i){
    		scanf("%s",str+L[i]);
    		x=strlen(str+L[i])+1; L[i+1]=L[i]+x;
    		insert(str+L[i],r1,i);
    	}
    	dfs(r1); clk=0;
    	for(int i=1;i<=n;++i)
    		rinsert(str+L[i+1]-2,r2,rk[i]);
    	dfs2(r2); ++n;
    	for(int i=1;i<=clk;++i)
    		if(!d[i]) rt[i]=rt[i-1]; 
    			else ins(1,n,rt[i-1],rt[i],d[i]);
    	scanf("%d",&m);
    	for(int x,y,lst=0;m--;){
    		scanf("%s",q);
    		x=g(r1,q,lst);
    		scanf("%s",q); y=strlen(q); reverse(q,q+y);
    		y=g(r2,q,lst);
    		lst=query(1,n,rt[wl[y]-1],rt[wr[y]],r[x]+1)-query(1,n,rt[wl[y]-1],rt[wr[y]],l[x]);
    		printf("%d
    ",lst);
    	}
    }

  • 相关阅读:
    c#結合正則表達式驗證輸入的字符串
    [SQL]数据库设计说明书模板
    如何在网页中插入Flv视频文件
    JAVASCRIPT常用检验代码
    Javascript知识精华
    提高Remoting的DataSet传输的性能
    如何快速的在SharePoint里构建一个Blog站点
    可爱的 Python,可爱的.NET
    郁闷的Xml Serialization BUG
    初试Zope(1)
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477108.html
Copyright © 2020-2023  润新知