歌名 - 歌手
0:00

    【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);
    }
    
    posted @ 2018-05-08 15:38  无尽的蓝黄  阅读(171)  评论(0编辑  收藏  举报