计蒜客 15500 阿里天池的新任务(简单) 题解

题意

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

wi={b,(wi1+a)modn,i=0i>0
​​

接下来,定义长度为 n 的 DNA 碱基序列 s(下标从 0 开始):

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)

其中 表示“且”关系, 表示“或”关系, a mod b 表示 a 除以 b 的余数。
现给定另一个 DNA 碱基序列 t,以及生成 s 的参数 n , a , b , L , R,求 t 在 s 中出现了多少次。

思路

根据公式生成s序列,然后进行KMP

代码

#include 
#include 
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(i1)
    {
        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;iif(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;
}

你可能感兴趣的:(计蒜客)