【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
",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
",(f[x][2])%mo);
		return 0;
	}
	else
		printf("%d
",f[x][1]%mo);
}
原文地址:https://www.cnblogs.com/chen1352/p/9008561.html