【GDOI2016模拟3.9】暴走的图灵机

题目

这里写图片描述

分析

我们发现当两个字符串合并时,a0a1表示左右两个字符串中有多少个TC表示合并处新增的T的个数,那么
a0=a1
a1=a0+a1+C
s0s1表示左右手两个字符串,那么每一次操作后左右手字符串分别为:

操作次数             左手  右手
  0                  s0   s1
  1                  s1   s0s1
  2                s0s1   s1s0s1
  3              s1s0s1   s0s1s1s0s1
  4          s0s1s1s0s1   s1s0s1s0s1s1s0s1
  5    s1s0s1s0s1s1s0s1   s0s1s1s0s1s1s0s1s0s1s1s0s1
  ···

然后我们发现,从第1次操作以后,每次合并处是以s1s1s1s0为一个循环。也就是说当|s0|>=m-1时,我们用KMP处理出a0a1以及s1s1s1s0合并时新增T的个数,然后O(N)递推一遍就可以了。
但是n<=10^9,只能拿60分。
因为递推时有循环,所以就可以构造矩阵,打个矩阵快速幂O(logN)。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const long long maxlongint=2147483647;
using namespace std;
char s[30000],s1[30000],s2[30000],t[30000];
long long n,m,tot,ans,mo,next[30000],f[2][5],lens=1,lens1=1,nn,nnn;
long long jz[5][5]=
{
{0,0,0,0,0},
{0,1,1,0,0},
{0,1,2,0,0},
{0,1,1,1,0},
{0,0,1,0,1} 
},b[5][5];
long long getnext()
{
    long long i,j,k;
    j=0;
    for(i=2;i<=m;i++)
    {
        while(j>0 && t[j+1]!=t[i]) j=next[j];
        if(t[j+1]==t[i]) j++;
        next[i]=j;
    }
}
long long kmp()
{
    long long i,j,k;
    getnext();
    j=0;
    for(i=1;i<=lens;i++)
    {
        while(j>0 && t[j+1]!=s[i]) j=next[j];
        if(t[j+1]==s[i]) j++;
        if(j==m) f[0][1]++;
    }
    j=0;
    for(i=1;i<=lens1;i++)
    {
        while(j>0 && t[j+1]!=s1[i]) j=next[j];
        if(t[j+1]==s1[i]) j++;
        if(j==m) f[0][2]++;
    }
}
long long kmp1()
{
    long long i,j,k;
    k=0;
    for(i=lens-m+2;i<=lens;i++)
        s2[++k]=s[i];
    for(i=1;i<=m-1;i++)
        s2[++k]=s1[i];
    j=0;
    for(i=1;i<=m+m-2;i++)
    {
        while(j>0 && t[j+1]!=s2[i]) j=next[j];
        if(t[j+1]==s2[i]) j++;
        if(j==m) f[0][0]++;
    }
    k=0;
    for(i=lens1-m+2;i<=lens1;i++)
        s2[++k]=s1[i];
    for(i=1;i<=m-1;i++)
        s2[++k]=s[i];
    j=0;
    for(i=1;i<=m+m-2;i++)
    {
        while(j>0 && t[j+1]!=s2[i]) j=next[j];
        if(t[j+1]==s2[i]) j++;
        if(j==m) f[0][3]++;
    }
    k=0;
    for(i=lens1-m+2;i<=lens1;i++)
        s2[++k]=s1[i];
    for(i=1;i<=m-1;i++)
        s2[++k]=s1[i];
    j=0;
    for(i=1;i<=m+m-2;i++)
    {
        while(j>0 && t[j+1]!=s2[i]) j=next[j];
        if(t[j+1]==s2[i]) j++;
        if(j==m) f[0][4]++;
    }
}
long long mi()
{
    long long x=0,y=1,i,j,k;
    while(nn>0)
    {
        if(nn&1==1)
        {   
            for(i=1;i<=4;i++)
            {
                f[x][i]=0;
                for(j=1;j<=4;j++)
                    f[x][i]=(f[x][i]+(f[y][j]*jz[j][i])%mo)%mo;
            }
            x=y;
            y=1-y;
        }
        for(i=1;i<=4;i++)
            for(j=1;j<=4;j++)
            {
                b[i][j]=0;
                for(k=1;k<=4;k++)
                {
                    b[i][j]=(b[i][j]+(jz[i][k]*jz[k][j])%mo)%mo;
                }
            }
        for(i=1;i<=4;i++)
            for(j=1;j<=4;j++)
            {
                jz[i][j]=b[i][j];
            }
        nn/=2;
    }
    return y;
}
int main()
{
    scanf("%d%d%d",&n,&m,&mo);
    scanf("%s",t+1);
    s[1]='0';
    s1[1]='1';
    long long i,j,k,l,x,y;
    for(j=1;j<=n;j++)
    {
        for(i=1;i<=lens1;i++)
            s2[i]=s1[i];
        for(i=1;i<=lens;i++)
            s1[i]=s[i];
        for(i=1;i<=lens1;i++)
        {
            s1[lens+i]=s2[i];
        }
        for(i=1;i<=lens1;i++)
            s[i]=s2[i];
        x=lens1;
        lens1+=lens;
        lens=x;
        y=j;
        if(lens>=m)
            break;
    }
    kmp();
    if(n==y)
    {
        printf("%d\n",f[0][1]%mo);
        return 0;
    }
    kmp1();
    f[1][1]=(f[0][2])%mo;
    f[1][2]=(f[0][1]+f[0][2]+f[0][0])%mo;
    f[1][3]=(f[0][3])%mo;
    f[1][4]=(f[0][4])%mo;
    n-=y+1;
    x=1;
    y=0;
    y=f[1][3];
    n-=0;
    nnn=n%2;
    nn=n/2;
    x=mi();
    if(nnn==1)
    {
        printf("%d\n",(f[x][2])%mo);
        return 0;
    }
    else
        printf("%d\n",f[x][1]%mo);
}

猜你喜欢

转载自www.cnblogs.com/chen1352/p/9008561.html