暴走的图灵机

版权声明:本文是蒟蒻写出来的,神犇转载也要说一声哦! https://blog.csdn.net/WerKeyTom_FTD/article/details/51121242

题目描述

这里写图片描述

做法

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]);
    }
}
阅读更多 登录后自动展开
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页