题意
阿里“天池”竞赛平台近日推出了一个新的挑战任务:对于给定的一串 DNA 碱基序列 t,判断它在另一个根据规则生成的 DNA 碱基序列 s 中出现了多少次。
首先,定义一个序列 w:
wi={b,(wi−1+a)modn,i=0i>0
接下来,定义长度为 n 的 DNA 碱基序列 s(下标从 0 开始):
si=⎧⎩⎨⎪⎪⎪⎪⎪⎪A,T,G,C,(L≤wi≤R)∧(wi mod 2=0)(L≤wi≤R)∧(wi mod 2=1)((wi<L)∨(wi>R))∧(wi mod 2=0)((wi<L)∨(wi>R))∧(wi mod 2=1)
其中 ∧ 表示“且”关系, ∨ 表示“或”关系, a mod b 表示 a 除以 b 的余数。
现给定另一个 DNA 碱基序列 t,以及生成 s 的参数 n , a , b , L , R,求 t 在 s 中出现了多少次。
思路
根据公式生成s序列,然后进行KMP
代码
#include <cstdio>
#include <cstring>
char s[1000001],t[1000001];
int next[1000001];
int n,a,b,L,R,w,ans,l;
void buildnext()
{
int i=1,tt=0;
next[1]=0;
while(i<l+1)
{
while(tt>0&&t[i-1]!=t[tt-1])
tt=next[tt];
tt++;
i++;
if(t[i-1]==t[tt-1])
next[i]=next[tt];
else next[i]=tt;
}
while(tt>0&&t[i-1]!=t[tt-1])
tt=next[tt];
tt++;
i++;
next[i]=tt;
}
int kmp()
{
int i=0,j=1,n=0;
int lt,ls;
lt=strlen(t);
ls=strlen(s);
while(lt+1-j<=ls-i)
{
if(s[i]==t[j-1])
{
i++;
j++;
if(j==lt+1)
{
n++;
j=next[j];
}
}
else
{
j=next[j];
if(j==0)
{
i++;
j++;
}
}
}
return n;
}
int main()
{
scanf("%d%d%d%d%d",&n,&a,&b,&L,&R);
scanf("%s",t);
for(int i=0;i<n;i++)
{
if(i==0)
w=b;
else w=(w+a)%n;
if(w>=L&&w<=R&&w%2==0)
s[i]='A';
else if(w>=L&&w<=R&&w%2==1)
s[i]='T';
else if(w%2==0)
s[i]='G';
else s[i]='C';
}
//printf("%s\n",s);
//printf("%s\n",t);
l=strlen(t);
buildnext();
printf("%d\n",kmp());
return 0;
}