BZOJ4641 基因改造[KMP]

这道题以前好像模拟的时候做过,当时不会做,于是用hash水过去了。。

正解是KMP,还是用当前字符与上一次相同字符位置的距离表示数组,于是数值相等时就代表相似。第一次出现用INF代替。

然后要匹配有多少个。暴力匹配的话是:匹配到$s_i,t_{j+1}$时,若$s_i=t_{j+1}$或者是$s_i>j$且$t_{j+1}>j$。这表示距离相同或者第一次出现时的匹配。

注意第一次出现的判断:因为从$s$串某一处开始,后面有的字符的距离值不是INF但与之相聚$d$的字符却不在匹配串范围内。

这就要求有上面那个条件。

于是KMP匹配,匹配成功一个字符的条件也就是上面那个。当我失配的时候,也保证是对的说。不太会讲,可以自己yy。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define dbg(x) cerr << #x << " = " << x <<endl
 7 using namespace std;
 8 typedef long long ll;
 9 typedef double db;
10 typedef pair<int,int> pii;
11 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
12 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
13 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
14 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
15 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
16 template<typename T>inline T read(T&x){
17     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
18     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
19 }
20 const int N=1e6+7,INF=114514810+1919;
21 int pres[N],pret[N],slas[N],tlas[N];
22 int nxt[N],ans[N],cnt;
23 int T,C,m,n;
24 
25 int main(){//freopen("5.in","r",stdin);freopen("5.ans","w",stdout);
26     read(T),read(C);while(T--){
27         read(n),read(m);
28         memset(slas,0,sizeof slas),memset(tlas,0,sizeof tlas);cnt=0;
29         for(register int i=1,x;i<=n;++i)read(x),pres[i]=slas[x]?i-slas[x]:INF,slas[x]=i;
30         for(register int i=1,x;i<=m;++i)read(x),pret[i]=tlas[x]?i-tlas[x]:INF,tlas[x]=i;
31         nxt[1]=0;int j=0;pret[m+1]=0,pres[n+1]=0;
32         for(register int i=2;i<=m;++i){
33             while(j&&!(pret[j+1]==pret[i]||pret[i]>j&&pret[j+1]>j))j=nxt[j];
34             nxt[i]=(pret[j+1]==pret[i]||pret[i]>j&&pret[j+1]>j)?++j:0;
35         }
36         j=0;
37         for(register int i=1;i<=n;++i){//dbg(i),dbg(j);
38             while(j&&!(pres[i]==pret[j+1]||pret[j+1]>j&&pres[i]>j))j=nxt[j];
39             (pres[i]==pret[j+1]||pret[j+1]>j&&pres[i]>j)&&(++j);
40             if(j==m)ans[++cnt]=i-j+1;
41         }
42         printf("%d\n",cnt);
43         for(register int i=1;i<=cnt;++i)printf("%d ",ans[i]);
44         puts("");
45     }
46     return 0;
47 }
View Code

 

posted @ 2019-09-10 16:40  Ametsuji_akiya  阅读(198)  评论(0编辑  收藏  举报