阿里“天池”竞赛平台近日推出了一个新的挑战任务:对于给定的一串 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 中出现了多少次。
输入格式
数据第一行为 5 个整数,分别代表 n,a,b,L,R。第二行为一个仅包含A
、T
、G
、C
的一个序列 t。
数据保证 0<a<n, 0≤b<n, 0≤L≤R<n, ∣t∣≤106,a,n 互质。
对于简单版本,1≤n≤106;
对于中等版本,1≤n≤109,a=1;
对于困难版本,1≤n≤109。
输出格式
输出一个整数,为 t 在 s 中出现的次数。
样例说明
对于第一组样例,生成的 s 为TTTCGGAAAGGCC
。
样例输入1
13 2 5 4 9
AGG
样例输出1
1
样例输入2
103 51 0 40 60
ACTG
样例输出2
5
分析:
用kmp算法即可
代码:
#include <stdio.h>
#include <string.h>
long long count=0;
long long next[1000005];
void get_next(char * s)
{
long long i=0,j=-1;
next[0]=-1;
long long len=strlen(s);
while(i<len)
{
if(j==-1||s[i]==s[j])
{
i++;j++;
if(s[i]==s[j])
next[i]=next[j];
else
next[i]=j;
}
else
{
j=next[j];
}
}
}
void kmp(char * str,char * str2)
{
long long i=-1,j=-1;
long long len2=strlen(str2);
long long len1=strlen(str);
while(i<len1)
{
if(j==-1||str[i]==str2[j])
{
i++;j++;
}
else
{
j=next[j];
}
if(j==len2)
{
count++;
j=next[j];
}
}
}
int main (){
char str[1000005];
char str2[1000005];
long long n,a,b,L,R;
long long wi;
scanf ("%lld%lld%lld%lld%lld",&n,&a,&b,&L,&R);
getchar();
scanf("%s",str2);
wi=b;// 生成序列
if (wi>=L&&wi<=R){
if (wi%2==0)
str[0]='A';
else
str[0]='T';
}
else {
if (wi%2==0)
str[0]='G';
else
str[0]='C';
}
for (long long i=1;i<n;i++){
wi=(wi+a)%n;
if (wi>=L&&wi<=R){
if (wi%2==0)
str[i]='A';
else
str[i]='T';
}
else {
if (wi%2==0)
str[i]='G';
else
str[i]='C';
}
}
get_next(str2);
kmp(str,str2);
printf ("%lld",count);
return 0;
}