zoukankan      html  css  js  c++  java
  • 【BZOJ4641】基因改造 KMP

    【BZOJ4641】基因改造

    Description

    "人类智慧的冰峰,只有萌萌哒的我寂寞地守望。"
    --TB
    TB正走在改造人类智慧基因的路上。TB发现人类智慧基因一点也不萌萌哒,导致人类普遍智商过低,为了拯救低智商人群,博爱的TB开始改造人类智慧基因。人类智慧DNA由C种人类智慧脱氧核苷酸构成(这是一种十分特殊的DNA)。TB智慧DNA片段T长度为M,她可以把另一段长度为M的人类智慧DNA片段S改造成T。改造过程中,TB可以充分发挥智慧,将任意两种人类智慧脱氧核苷酸交换(比如对于片段S=12321,交换1和2变成S=21312,交换1和4变成42324),可以无限次交换。如果S可以通过若干次交换变成T,那么就称S为"萌萌哒人类基因片段"。TB想知道对于一个长度为N的人类智慧DNA片段S[1~N],有多少个长度为M的连续子片段S[i~i+M-1],是"萌萌哒人类基因片段",并且这些"萌萌哒人类基因片段"在哪里。

    Input

    输入文件的第一行包含两个正整数case和C,分别表示数据组数和人类智慧脱氧核苷酸的种数。
    接下来3*case行,每三行表示一组数据:
    第一行一个正整数N和M,表示人类智慧DNA片段S和TB智慧DNA片段T的长度。
    第二行N个正整数,表示人类智慧DNA片段S。
    第三行M个正整数,表示TB智慧DNA片段T。
    对于所有数据数据,case=3, n,m,C<=1000000

    Output

    对于每组数据:
    第一行一个正整数tot,表示"萌萌哒人类基因片段"的个数。
    接下来一行tot个用空格隔开的正整数pos,表示"萌萌哒人类基因片段"开头所在的位置。要求从小到大输出每个pos。

    Sample Input

    3 3
    6 3
    1 2 1 2 3 2
    3 1 3
    6 3
    1 2 1 2 1 2
    3 1 3
    6 3
    1 1 2 1 2 1
    3 1 3

    Sample Output

    3
    1 2 4
    4
    1 2 3 4
    3
    2 3 4
    对于第一组数据:
    S[1~3]=121,可以先将1和2交换变成212,再将2和3交换变成313。
    S[2~4]=212,可以将2和3交换变成313。
    S[4~6]=232,可以先将2和3交换变成323,再将1和2交换变成313。

    题解:这种题多做做就差不多能掌握套路了。

    显然我们将KMP的比较函数改一改即可,不难想到用pre[i],即i上一次出现的位置来当做判相等的条件。特别地,如果pre[i]超出了S与T匹配的范围,则我们视为pre[i]=-1。细节还是需要注意一下的~

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    
    using namespace std;
    const int maxn=1000010;
    int cas,n,m,C,tot;
    int next[maxn],p1[maxn],p2[maxn],pos[maxn],last[maxn];
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    void work()
    {
    	n=rd(),m=rd(),tot=0;
    	int i,j,a;
    	memset(last,-1,sizeof(last));
    	for(i=0;i<n;i++)	a=rd(),p1[i]=(last[a]==-1)?-1:i-last[a],last[a]=i;
    	memset(last,-1,sizeof(last));
    	for(i=0;i<m;i++)	a=rd(),p2[i]=(last[a]==-1)?-1:i-last[a],last[a]=i;
    	next[0]=-1,i=0,j=-1;
    	p1[n]=p2[m]=0;
    	while(i<m)
    	{
    		if(j==-1||p2[i]==p2[j]||(p2[i]>j&&p2[j]==-1))	next[++i]=++j;
    		else	j=next[j];
    	}
    	i=j=0;
    	while(i<n)
    	{
    		if(j==-1||p1[i]==p2[j]||(p1[i]>j&&p2[j]==-1))	i++,j++;
    		else	j=next[j];
    		if(j==m)	pos[++tot]=i-m+1;
    	}
    	printf("%d
    ",tot);
    	for(i=1;i<=tot;i++)	printf("%d ",pos[i]);
    	printf("
    ");
    }
    int main()
    {
    	cas=rd(),C=rd();
    	while(cas--)	work();
    	return 0;
    }//3 3 6 3 1 2 1 2 3 2 3 1 3 6 3 1 2 1 2 1 2 3 1 3 6 3 1 1 2 1 2 1 3 1 3

     

  • 相关阅读:
    Leetcode 349. Intersection of Two Arrays
    hdu 1016 Prime Ring Problem
    map 树木品种
    油田合并
    函数学习
    Leetcode 103. Binary Tree Zigzag Level Order Traversal
    Leetcode 102. Binary Tree Level Order Traversal
    Leetcode 101. Symmetric Tree
    poj 2524 Ubiquitous Religions(宗教信仰)
    pat 1009. 说反话 (20)
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7670080.html
Copyright © 2011-2022 走看看