阿里“天池”竞赛平台近日推出了一个新的挑战任务:对于给定的一串 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就是关于字符串匹配的算法;
题意:头一次见这种题型,总共有四道题,后三道是一样的,只是数据范围不同;这里是第二道题,暴力kmp就可;
思路:按照题意生成字符串s,然后匹配s与t;因为本题对于样例 sss ss 输出的是2,我的模板不能过计算重叠的(我是了解会套模板,不会修改),这里使用的是kuangbin的模板;
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1000006;
char s[maxn],t[maxn];
int w[maxn];
int nextt[maxn];
int m,n;
int N,a,b,l,r;
void kmp_pre(char x[],int m,int nextt[])
{
int i,j;
j=nextt[0]=-1;
i=0;
while(i<m)
{
while(-1!=j&&x[i]!=x[j])
j=nextt[j];
nextt[++i]=++j;
}
}
int kmp_count(char x[],int m,char y[],int n)
{
int i,j;
int ans=0;
kmp_pre(x,m,nextt);
i=j=0;
while(i<n)
{
while(-1!=j&&y[i]!=x[j])
j=nextt[j];
i++,j++;
if(j>=m)
{
ans++;
j=nextt[j];
}
}
return ans;
}
int main()
{
scanf("%d%d%d%d%d",&N,&a,&b,&l,&r);
w[0]=b;
for(int i=1;i<N;i++)
w[i]=(w[i-1]+a)%N;
for(int i=0;i<N;i++)
{
if((w[i]>=l&&w[i]<=r)&&w[i]%2==0)
s[i]='A';
else if((w[i]>=l&&w[i]<=r)&&w[i]%2==1)
s[i]='T';
else if((w[i]<l||w[i]>r)&&w[i]%2==0)
s[i]='G';
else if((w[i]<l||w[i]>r)&&w[i]%2==1)
s[i]='C';
}
scanf("%s",&t);
n=strlen(s),m=strlen(t);
int ans=kmp_count(t,m,s,n);
printf("%d\n",ans);
return 0;
}