計ニンニク客15500阿里天池の新しい任務(簡単)の題解

4764 ワード

に言及
アリの「天池」コンテストプラットフォームは最近、与えられた一連の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)((wiR))∧(wi mod 2=0)((wiR))∧(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
",s);
//printf("%s
",t);
l=strlen(t); buildnext(); printf("%d
"
,kmp()); return 0; }