2017 计蒜之道 初赛 第一场 B题(阿里天池的新任务)


阿里“天池”竞赛平台近日推出了一个新的挑战任务:对于给定的一串 DNA 碱基序列 tt,判断它在另一个根据规则生成的 DNA 碱基序列 ss 中出现了多少次。

首先,定义一个序列 ww

\displaystyle w_{i} = \begin{cases}b, & i = 0\\(w_{i-1} + a) \mod n, & i > 0\end{cases}wi={b,(wi1+a)modn,i=0i>0

接下来,定义长度为 nn 的 DNA 碱基序列 ss(下标从 00 开始):

\displaystyle s_{i} = \begin{cases}A , & (L \le w_{i} \le R) \land (w_{i}\ \mathrm{mod}\ 2 = 0)\\T , & (L \le w_{i} \le R) \land (w_{i}\ \mathrm{mod}\ 2 = 1)\\G , & ((w_{i} < L) \lor (w_{i} > R)) \land (w_{i}\ \mathrm{mod}\ 2 = 0)\\C , & ((w_{i} < L) \lor (w_{i} > R)) \land (w_{i}\ \mathrm{mod}\ 2 = 1)\end{cases}si=A,T,G,C,(LwiR)(wi mod 2=0)(LwiR)(wi mod 2=1)((wi<L)(wi>R))(wi mod 2=0)((wi<L)(wi>R))(wi mod 2=1)

其中 \land 表示“且”关系,\lor 表示“或”关系,a\ \mathrm{mod}\ ba mod b 表示 aa 除以 bb 的余数。

现给定另一个 DNA 碱基序列 tt,以及生成 ss 的参数 n , a , b , L , Rn,a,b,L,R,求 tt 在 ss 中出现了多少次。

输入格式

数据第一行为 55 个整数,分别代表 n , a , b , L , Rn,a,b,L,R。第二行为一个仅包含ATGC的一个序列 tt

数据保证 0 < a < n,0<a<n, 0 \le b < n,0b<n, 0 \le L \le R < n,0LR<n, |t| \le 10^{6}t106a,na,n 互质。

对于简单版本,1 \leq n \leq 10^{6}1n106

对于中等版本,1 \leq n \leq 10^{9}, a = 11n109,a=1

对于困难版本,1 \leq n \leq 10^{9}1n109

输出格式

输出一个整数,为 tt 在 ss 中出现的次数。

样例说明

对于第一组样例,生成的 ss 为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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值