m代表T串的长度。
一个显然的做法是设g[i]表示i次操作后左手串所包含T串的个数。
则g[i]=g[i-2]+g[i-1]+c
其中c表示跨越中间线(即隔开i-2和i-1次操作后左手串的那条线)的所有串中T串的数量。
设f[i]表示i次操作后左手串的长度。
仔细观察发现,当f[i-2]和f[i-1]都不小于m后,c的循环节为2。
然后先暴力找到最早的id满足f[id]比2m-2大,然后矩阵乘法。
#include<cstdio>
#include<algorithm>
#include<stack>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long LL;
const int maxn=100+10,maxm=50000+10;
int f[maxn],g[maxn],next[maxm];
bool pre[maxn][maxm],suc[maxn][maxm],s[maxm],ss[maxm];
int i,j,k,l,t,n,m,p,ans,id,c1,c2;
stack<int> sta;
char ch;
struct matrix{
int a[5][5];
};
matrix operator *(matrix a,matrix b){
matrix c;
int i,j,k;
fo(i,0,4)
fo(j,0,4) c.a[i][j]=0;
fo(k,1,4)
fo(i,1,4)
fo(j,1,4)
c.a[i][j]=(c.a[i][j]+(LL)a.a[i][k]*b.a[k][j]%p)%p;
return c;
}
matrix a,dis,c,one,tt;
int kmp(bool *a,int n,bool *b,int m){
int ans=0,i,j;
j=0;
next[1]=0;
fo(i,2,m){
while (j&&b[j+1]!=b[i]) j=next[j];
if (b[j+1]==b[i]) j++;
next[i]=j;
}
j=0;
fo(i,1,n){
while (j&&b[j+1]!=a[i]) j=next[j];
if (b[j+1]==a[i]) j++;
if (j==m){
ans=(ans+1)%p;
j=next[j];
}
}
return ans;
}
matrix quicksortmi(matrix x,int y){
if (y==0) return one;
tt=quicksortmi(x,y/2); tt=tt*tt; if (y%2) tt=tt*x; return tt; } int main(){ scanf("%d%d%d",&n,&m,&p); ch=getchar(); while (ch!='0'&&ch!='1') ch=getchar(); s[1]=ch-'0'; fo(i,2,m){ ch=getchar(); s[i]=ch-'0'; } f[0]=f[1]=1; fo(i,2,n){ if (f[i-1]+f[i-2]>1000000) f[i]=1000000;else f[i]=f[i-1]+f[i-2]; if (f[i]>m*5) break; } pre[0][1]=suc[0][1]=0; pre[1][1]=suc[1][1]=1; if (m==1){ if (s[1]) g[1]=1%p;else g[0]=1%p; } fo(i,2,n){ g[i]=(g[i-2]+g[i-1])%p; if (f[i-1]<m){ fo(j,1,f[i-2]) ss[j]=pre[i-2][j]; fo(j,1,f[i-1]) ss[f[i-2]+j]=pre[i-1][j]; g[i]=(g[i]+kmp(ss,f[i],s,m))%p; fo(j,1,min(f[i],m-1)) pre[i][j]=ss[j]; t=0; fo(j,max(f[i]-m+2,1),f[i]) suc[i][++t]=ss[j]; } else if (f[i-2]<m){ fo(j,1,f[i-2]) ss[j]=pre[i-2][j]; fo(j,1,m-1) ss[f[i-2]+j]=pre[i-1][j]; g[i]=(g[i]+kmp(ss,f[i-2]+m-1,s,m))%p; fo(j,1,m-1) pre[i][j]=ss[j]; fo(j,1,m-1) suc[i][j]=suc[i-1][j]; } else{ fo(j,1,m-1) ss[j]=suc[i-2][j]; fo(j,1,m-1) ss[j+m-1]=pre[i-1][j]; g[i]=(g[i]+kmp(ss,2*m-2,s,m))%p; fo(j,1,m-1) pre[i][j]=pre[i-2][j]; fo(j,1,m-1) suc[i][j]=suc[i-1][j]; id=i; break; } } if (id==n) printf("%d\n",g[n]); else{ fo(i,1,m-1) ss[i]=suc[id-1][i]; fo(i,1,m-1) ss[i+m-1]=pre[id-2][i]; c1=kmp(ss,2*m-2,s,m); fo(i,1,m-1) ss[i+m-1]=pre[id-1][i]; c2=kmp(ss,2*m-2,s,m); a.a[1][1]=g[id-1]; a.a[1][2]=g[id]; a.a[1][3]=c1; a.a[1][4]=c2; fo(i,0,4) a.a[0][i]=0; fo(i,2,4) fo(j,0,4) a.a[i][j]=0; dis.a[1][1]=dis.a[2][1]=dis.a[3][1]=1; dis.a[2][2]=2; dis.a[1][2]=dis.a[3][2]=dis.a[4][2]=1; dis.a[3][3]=dis.a[4][4]=1; //dis.a[4][1]=dis.a[1][3]=dis.a[2][3]=dis.a[4][3]=dis.a[1][4]=dis.a[2][]
fo(i,1,4) one.a[i][i]=1;
/*c=a*quicksortmi(dis,(n-id)/2);
if ((n-id)%2) printf("%d\n",((c.a[1][1]+c.a[1][2])%p+c1)%p);else printf("%d\n",c.a[1][2]);*/
/*c=a*quicksortmi(dis,(n-id+1)/2);
if ((n-id)%2) printf("%d\n",c.a[1][1]);else printf("%d\n",c.a[1][2]);*/
/*fo(i,1,(n-id+1)/2) a=a*dis;
if ((n-id)%2) printf("%d\n",a.a[1][1]);else printf("%d\n",a.a[1][2]);*/
/*tt=one;
fo(i,1,(n-id+1)/2) tt=tt*dis;
c=a*tt;
if ((n-id)%2) printf("%d\n",c.a[1][1]);else printf("%d\n",c.a[1][2]);*/
l=(n-id+1)/2;
while (l){
sta.push(l%2);
l/=2;
}
tt=one;
while (!sta.empty()){
tt=tt*tt;
if (sta.top()==1) tt=tt*dis;
sta.pop();
}
c=a*tt;
if ((n-id)%2) printf("%d\n",c.a[1][1]);else printf("%d\n",c.a[1][2]);
}
}