zoukankan      html  css  js  c++  java
  • kuangbin-kmp专题

     题意:给你两个串,问你第一个串在第二个串出现的次数

    解题思路:模板题

    代码

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int maxn=1e6+100;
    const int maxm=1e4+100;
    char s[maxn];
    char t[maxm];
    int _next[maxm];
    int slen,tlen;
    void get_next()
    {
        memset(_next,0,sizeof(_next));
        int j,k;//k代表的是相同字符的长度;
        j=0;k=-1;_next[0]=-1;
        while(j<tlen)//计算模式串的next数组,也就是每个字符若是匹配失败,该跳的位置;
        {
            if(k==-1||t[j]==t[k])//如果相等等于之前的+1;
                _next[++j]=++k;
            else
                k=_next[k];//如果不相等,跳转到k=next[k]去;把指针转移到之前的相同串去,保证最大前缀
        }
    }
    int kmp_count()
    {
        int ans=0,i=0,j=0;
        if(slen==1&&tlen==1)
        {
            if(s[0]==t[0])
                return 1;
            else
                return 0;
        }
        get_next();
        while(i<slen)
        {
            if(j==-1||s[i]==t[j])
            {
                i++;j++;
            }
            else
                j=_next[j];
            if(j==tlen)
            {
                ans++;
                j=_next[j];
            }
        }
        return ans;
    }
    int main()
    {
        int tt;
        scanf("%d",&tt);
        while(tt--)
        {
            scanf("%s%s",t,s);
            tlen=strlen(t);slen=strlen(s);
            cout<<kmp_count()<<endl;
        }
    }

    B - Number Sequence

     HDU - 1711 

    题意:给你两个数字字符串,问你第二个串在第一个串首次出现的位置

    解题思路:模板题

    代码

    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<vector>
    #include<map>
    #include<set>
    #include<iostream>
    using namespace std;
    const int maxn=1e6+100;
    const int maxm=1e4+100;
    int t[maxm],s[maxn];
    int tlen,slen,_next[maxm];
    void get_next()
    {
        int j=0,k=-1;_next[0]=-1;
        while(j<tlen)
        {
            if(k==-1||t[k]==t[j])
                _next[++j]=++k;
            else
                k=_next[k];
        }
    }
    
    int kmp_pos()
    {
        int i=0,j=0;
        get_next();
        while(i<slen&&j<tlen)
        {
            if(j==-1||s[i]==t[j])//如果匹配没出问题,直接匹配
            {
                i++;j++;
            }
            else//如果匹配出现了问题,那么直接跳转到next[j]来,因为next[j]等于当前最长的公共前后缀,所以在公共后缀前面的那一部分没必要匹配了;
                j=_next[j];
        }
        if(j==tlen)
            return i-tlen;
        return -1;
    
    }
    int main()
    {
        int tt;
        scanf("%d",&tt);
        while(tt--)
        {
            scanf("%d%d",&slen,&tlen);
            fill(_next,_next+tlen,0);
            for(int i=0;i<slen;i++)
                scanf("%d",&s[i]);
            for(int i=0;i<tlen;i++)
                scanf("%d",&t[i]);
            if(kmp_pos()==-1)
                cout<<-1<<endl;
            else
            cout<<kmp_pos()+1<<endl;
        }
    }

    C - Period

     POJ - 1961 

    题意:给你一个字符串,问你当前长度i的前缀是否是循环字符串,是的话输出循环节的次数

    解题思路:当前i的最小循环节为i-next[i],算出当前的next数组就行了

    代码

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<iostream>
    #include<string>
    using namespace std;
    const int maxn=1e6+100;
    char t[maxn];
    int _next[maxn],tlen;
    
    void get_next()
    {
        fill(_next,_next+tlen,0);
        int j=0,k=-1;_next[0]=-1;
        while(j<tlen)
        {
            if(k==-1||t[j]==t[k])
                _next[++j]=++k;
            else
                k=_next[k];
        }
    }
    int main()
    {
        int tt=0;
        while(scanf("%d",&tlen)!=EOF)
        {if(tlen==0)
                break;
            tt++;
    
    
            scanf("%s",t);
            get_next();cout<<"Test case #"<<tt<<endl;
            for(int i=1;i<=tlen;i++)
            {
                int t=i-_next[i];
                if(i%t==0&&i/t!=1)
                {
                    cout<<i<<" "<<i/t<<endl;
                }
            }
            cout<<endl;
        }
    
    }

     题意:求最小循环节出现的次数

    解题思路:最小循环节=i-next[i];

    代码

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<iostream>
    #include<string>
    using namespace std;
    const int maxn=1e6+100;
    char t[maxn];
    int _next[maxn],tlen;
    
    void get_next()
    {
        fill(_next,_next+tlen,0);
        int j=0,k=-1;_next[0]=-1;
        while(j<tlen)
        {
            if(k==-1||t[j]==t[k])
                _next[++j]=++k;
            else
                k=_next[k];
        }
    }
    int main()
    {
        int tt=0;
        while(scanf("%d",&tlen)!=EOF)
        {if(tlen==0)
                break;
            tt++;
    
    
            scanf("%s",t);
            get_next();cout<<"Test case #"<<tt<<endl;
            for(int i=1;i<=tlen;i++)
            {
                int t=i-_next[i];
                if(i%t==0&&i/t!=1)
                {
                    cout<<i<<" "<<i/t<<endl;
                }
            }
            cout<<endl;
        }
    
    }

    E - Count the string

     HDU - 3336 

    题意:给你一个字符串,问你前缀出现的次数和

    解题思路:dp+kmp,dp[i]表示当前字符子串包含的前缀出现的次数和

    代码

    void get_next()
    {
        int j=0,k=-1;_next[0]=-1;
        while(j<tlen)
        {
            if(k==-1||t[j]==t[k])
            {
                _next[++j]=++k;
            }
            else
                k=_next[k];
        }
    }
    int main()
    {
        scanf("%d",&tt);
        while(tt--)
        {
            memset(_next,0,sizeof(_next));
            memset(dp,0,sizeof(dp));
            scanf("%d",&tlen);
            scanf("%s",t);
            get_next();
            for(int i=1;i<=tlen;i++)
                dp[i]=1;
            for(int i=1;i<=tlen;i++)
            {
                if(_next[i]==0)
                continue;
                else
                    dp[i]=dp[i]+dp[_next[i]];
                dp[i]%=mod;
            }
            int ans=0;
            for(int i=1;i<=tlen;i++)
                {
                    ans+=dp[i];ans%=mod;
                }
            cout<<ans<<endl;
        }
    }

    F - Cyclic Nacklace

     HDU - 3746

    题意:问你补充多少个字符,可以使得这个字符串变成循环串

    解题思路:找到最小循环节,然后len%(最小循环节)

    代码

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<string>
    #include<iostream>
    using namespace std;
    const int maxn=2e5+100;
    int n,tlen;
    int _next[maxn];
    char t[maxn];
    void get_next()
    {
        int j,k;
        j=0;k=-1;_next[0]=-1;
        while(j<tlen)
        {
            if(k==-1||t[j]==t[k])
                _next[++j]=++k;
            else
                k=_next[k];
        }
    }
    int main()
    {
        scanf("%d",&n);
        while(n--)
        {
            scanf("%s",t);tlen=strlen(t);
            get_next();
            int tmp=tlen-_next[tlen];
            if(tlen%tmp==0)
            {
                if((tlen/tmp)!=1)
                    cout<<0<<endl;
                else
                    cout<<tlen<<endl;
            }
            else
            {
                cout<<tmp-tlen%tmp<<endl;
            }
        }
    }

    G - Simpsons’ Hidden Talents

     HDU - 2594

    题意:给你两个字符串,问你最长的相同前后缀

    解题思路:一直匹配下去,看到最后j的值决定

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int maxn=1e5+100;
    char s[maxn],t[maxn];
    int _next[maxn],slen,tlen;
    void get_next()
    {
        int j=0,k=-1;_next[0]=-1;
        while(j<tlen)
        {
            if(k==-1||t[j]==t[k])
                _next[++j]=++k;
            else
                k=_next[k];
        }
    }
    void pre()
    {
        int i=0,j=0;
        get_next();
        while(i<slen)
        {
            if(j==-1||s[i]==t[j])
            {
                i++;j++;
            }
            else
                j=_next[j];
        }
        if(j==0)
            cout<<j<<endl;
        else
        {
            for(int k=0;k<j;k++)
                cout<<t[k];
            cout<<" "<<j<<endl;
        }
    }
    int main()
    {
        while(scanf("%s %s",t,s)!=EOF)
        {
            tlen=strlen(t);slen=strlen(s);
            pre();
        }
    }

    H - Milking Grid

     POJ - 2185

    题意:给你一个矩阵字符串,找到最小的矩阵循环节

    解题思路:首先求出行的每行最小循环节最大值,再求出每列的最小循环节最大值,这两个值相乘就是答案

    代码

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<iostream>
    using namespace std;
    int n,m,tlen;
    char s[10050][80];
    char t[10050];
    int _next[10050][80],_next2[80][10050];
    void get_next(int pos,int flag)
    {
        int j,k;
        j=0;k=-1;
        if(flag==0)
        {
            _next[pos][0]=-1;
            while(j<tlen)
            {
                if(k==-1||t[j]==t[k])
                    _next[pos][++j]=++k;
                else
                    k=_next[pos][k];
            }
        }
        else if(flag==1)
        {
            _next2[pos][0]=-1;
            while(j<tlen)
            {
                if(k==-1||t[j]==t[k])
                    _next2[pos][++j]=++k;
                else
                    k=_next2[pos][k];
            }
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
            scanf("%s",s[i]);
        int maxxc=-1;
        int maxxr=-1;
        for(int i=0;i<n;i++)
        {
            tlen=m;
            for(int j=0;j<m;j++)
                t[j]=s[i][j];
            get_next(i,0);
            int tmp=tlen-_next[i][tlen];
            maxxc=max(maxxc,tmp);
        }
        for(int j=0;j<m;j++)
        {
            tlen=n;
            for(int i=0;i<n;i++)
                t[i]=s[i][j];
            get_next(j,1);
            int tmp=tlen-_next2[j][tlen];
            maxxr=max(maxxr,tmp);
        }
        cout<<maxxr*maxxc<<endl;
    }

     题意:给你一个字符串,找一个最长子串,既是前缀,又是后缀,还出现在前后缀中间;

    解题思路:先从前后缀开始找起,用next数组一直递推,知道相同前后缀的长度不超过字符串长度的一半,标记,然后,暴力匹配找出中间的

    代码

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<string>
    #include<iostream>
    using namespace std;
    const int maxn=1e6+100;
    char t[maxn];
    int flag[maxn];
    int _next[maxn];
    int tlen,n;
    void get_next()
    {
        int j=0,k=-1;
        _next[0]=-1;
        while(j<tlen)
        {
            if(k==-1||t[j]==t[k])
                _next[++j]=++k;
            else
                k=_next[k];
        }
    }
    int main()
    {
        scanf("%d",&n);
        while(n--)
        {
            memset(flag,0,sizeof(flag));
            memset(_next,0,sizeof(_next));
            scanf("%s",t);
            tlen=strlen(t);
            get_next();
            int tmp=tlen;
            while(tmp>0)
            {
                if(tmp*2<=tlen)
                    flag[tmp]=1;
                tmp=_next[tmp];
            }
            int ans=0;
            for(int i=tlen-1;i>=0;i--)
            {
                tmp=i;
                while(tmp>0)
                {
                    if(flag[tmp]&&tmp*2<=i&&i+tmp<=tlen)
                    {
                        ans=max(ans,tmp);
                    }
                    tmp=_next[tmp];
                }
            }
            cout<<ans<<endl;
        }
    }

     题意:给你两个字符串,问你第二个串的每一个后缀在第一个串出现的次数

    解题思路:把两个串反转,就变成了求前缀的问题,用一个数组cnt计算每次匹配的位置出现的次数,然后反着递推一边

    代码

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
    const ll mod=1e9+7;
    const int maxn=1e6+100;
    char s[maxn];
    char t[maxn];
    int _next[maxn];
    int slen,tlen;
    ll sum;
    ll cnt[maxn];
    void get_next()
    {
        memset(_next,0,sizeof(_next));
        int j,k;//k代表的是相同字符的长度;
        j=0;k=-1;_next[0]=-1;
        while(j<tlen)//计算模式串的next数组,也就是每个字符若是匹配失败,该跳的位置;
        {
            if(k==-1||t[j]==t[k])//如果相等等于之前的+1;
                _next[++j]=++k;
            else
                k=_next[k];//如果不相等,跳转到k=next[k]去;把指针转移到之前的相同串去,保证最大前缀
        }
    }
    int kmp_count()
    {
        ll ans=0,i=0,j=0;
        if(slen==1&&tlen==1)
        {
            if(s[0]==t[0])
                return 1;
            else
                return 0;
        }
        get_next();
        while(i<slen)
        {
            if(j==-1||s[i]==t[j])
            {
                i++;j++;
            }
            else
                j=_next[j];
            cnt[j]++;
            if(j==tlen)
            {
                j=_next[j];
            }
        }
        for(int i=tlen;i>0;i--)
        {
            cnt[_next[i]]=cnt[_next[i]]+cnt[i];
        }
        for(int i=1;i<=tlen;i++)
            ans+=(i*cnt[i])%mod;
        ans%=mod;
        return ans;
    }
    int main()
    {
        int tt;
        scanf("%d",&tt);
        while(tt--)
        {
            memset(cnt,0,sizeof(cnt));
            scanf("%s%s",s,t);
            tlen=strlen(t);slen=strlen(s);
            reverse(s,s+slen);reverse(t,t+tlen);
            cout<<kmp_count()<<endl;
        }
    }

    K - Bazinga

     HDU - 5510 

    题意:给你n和字符串,让你求出一个字符串,他前面的字符串中,存在不是他的子串的字符串,输出这个字符串的位置,多个就输出最晚出现的那个;

    解题思路:暴力求会超时,所以用一个标记数组,标记之前成功匹配的字符串,因为之前成功过,说明后来的串更大,直接匹配当前串与更大的串,失败就GG,成功说明标记串不用匹配了,因为是子串的子串,也是子串

    代码

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<iostream>
    using namespace std;
    char a[550][2050];
    int tlen,slen;
    int s[2050],t[2050];
    int _next[2050];
    int visit[550];
    void get_next(int x,int y)
    {
        memset(_next,0,sizeof(_next));
        int j,k;//k代表的是相同字符的长度;
        j=0;k=-1;_next[0]=-1;
        tlen=strlen(a[x]);
        slen=strlen(a[y]);
        while(j<tlen)//计算模式串的next数组,也就是每个字符若是匹配失败,该跳的位置;
        {
            if(k==-1||a[x][j]==a[x][k])//如果相等等于之前的+1;
                _next[++j]=++k;
            else
                k=_next[k];//如果不相等,跳转到k=next[k]去;把指针转移到之前的相同串去,保证最大前缀
        }
    }
    int kmp_pos(int x,int y)
    {
        int i=0,j=0;
        get_next(x,y);
        while(i<slen&&j<tlen)
        {
            if(j==-1||a[y][i]==a[x][j])//如果匹配没出问题,直接匹配
            {
                i++;j++;
            }
            else//如果匹配出现了问题,那么直接跳转到next[j]来,因为next[j]等于当前最长的公共前后缀,所以在公共后缀前面的那一部分没必要匹配了;
                j=_next[j];
            if(j==tlen)
            return i-tlen;
        }
    
        return -1;
    
    }
    int main()
    {
        int tt;
        int n;
        int cot=0;
        scanf("%d",&tt);
        while(tt--)
        {
            memset(visit,0,sizeof(visit));
            cot++;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
                scanf("%s",a[i]);
            int flag=0;
            int ans=-1;
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=i-1;j++)
                {
                    if(visit[j]==1)
                        continue;
                    if(kmp_pos(j,i)==-1)
                        ans=i;
                    else
                        visit[j]=1;
                }
            }
            cout<<"Case #"<<cot<<": ";
            cout<<ans<<endl;
        }
    }

    L - Blue Jeans

     POJ - 3080 

    题意:给你n个长度都为60的母串,让你求出这些母串中最长的公共子串

    解题思路:暴力。。。找一个母串,暴力他所有的子串进行kmp就行了

    代码

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    char a[15][100];
    char t[100];
    char s[100];
    char char_ans[100];
    int next[100];
    int slen,tlen;
    bool bj(char x[],char y[],int w)
    {
        for(int i=0;i<w;i++)
        {
            if(x[i]==y[i])
                continue;
            if(x[i]>y[i])
            {
                return true;
            }
        }
        return false;
    }
    void get_next()
    {
        int j=0,k=-1;next[0]=-1;
        while(j<tlen)
        {
            if(k==-1||t[k]==t[j])
                next[++j]=++k;
            else
                k=next[k];
        }
    }
    int kmp_pos()
    {
        int i=0,j=0;
        get_next();
        while(i<slen&&j<tlen)
        {
            if(j==-1||s[i]==t[j])
            {
                i++;j++;
            }
            else
                j=next[j];
        }
        if(j==tlen)
            return i-tlen;
        else
            return -1;
    }
    int main()
    {
        int tt,n;
        int ans=-1;
        int cnt;
        int flag;
        scanf("%d
    ",&tt);
        while(tt--)
        {
            ans=-1;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                scanf("%s",a[i]);
            }
            for(int i=0;i<=59;i++)//从位置i开始
            {
                cnt=0;tlen=0;
                for(int j=i;j<=59;j++)//到位置j结束
                {
                    slen=60;
                    t[cnt]=a[1][j];tlen++;cnt++;
                    flag=0;
                    for(int k=2;k<=n;k++)//循环n个串找字串;
                    {
                        for(int l=0;l<60;l++)//s串的赋值;
                            s[l]=a[k][l];
                        int x=kmp_pos();
                        if(x==-1)
                            flag=1;
                    }
                    if(flag==0)
                    {
                        if(tlen==ans)
                        {
                            if(bj(t,char_ans,tlen))
                               {
                                   for(int k=0;k<tlen;k++)
                                    char_ans[k]=t[k];
                               }
                        }
                        else if(tlen>ans)
                        {
                            ans=tlen;
                            for(int k=0;k<tlen;k++)
                                    char_ans[k]=t[k];
                        }
                    }
                }
            }
            if(ans<3)
                printf("no significant commonalities
    ");
            else
            {
                for(int i=0;i<ans;i++)
                    printf("%c",char_ans[i]);
                printf("
    ");
            }
        }
    }

    M - Substring Frequency

     LightOJ - 1255

    题意:两个串,求第二个串出现的次数

    解题思路:模板题

    代码

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn=1e6+100;
    char s[maxn],t[maxn];
    int _next[maxn];
    int slen,tlen;
    void get_next()
    {
        int j,k;//k代表的是相同字符的长度;
        j=0;k=-1;_next[0]=-1;
        while(j<tlen)//计算模式串的next数组,也就是每个字符若是匹配失败,该跳的位置;
        {
            if(k==-1||t[j]==t[k])//如果相等等于之前的+1;
                _next[++j]=++k;
            else
                k=_next[k];//如果不相等,跳转到k=next[k]去;把指针转移到之前的相同串去,保证最大前缀
        }
    }
    int kmp_pos()
    {
        int i=0,j=0;
        get_next();
        while(i<slen&&j<tlen)
        {
            if(j==-1||s[i]==t[j])//如果匹配没出问题,直接匹配
            {
                i++;j++;
            }
            else//如果匹配出现了问题,那么直接跳转到next[j]来,因为next[j]等于当前最长的公共前后缀,所以在公共后缀前面的那一部分没必要匹配了;
                j=_next[j];
        }
        if(j==tlen)
            return i-tlen;
        return -1;
    
    }
    int kmp_count()
    {
        int ans=0,i=0,j=0;
        if(slen==1&&tlen==1)
        {
            if(s[0]==t[0])
                return 1;
            else
                return 0;
        }
        get_next();
        for(i=0;i<slen;i++)
        {
            while(j>0&&s[i]!=t[j])
                j=_next[j];
            if(s[i]==t[j])
                j++;
            if(j==tlen)
            {
                ans++;
                j=_next[j];
            }
        }
        return ans;
    }
    int main()
    {
        int tt;
        scanf("%d",&tt);
        int cot=0;
        while(tt--)
        {
            cot++;
            scanf("%s %s",s,t);
            slen=strlen(s);
            tlen=strlen(t);
            cout<<"Case "<<cot<<": ";
            cout<<kmp_count()<<endl;
        }
    }

    N - Making Huge Palindromes

     LightOJ - 1258

    题意:问你补充多少个字符+上原先的字符=一个回文串,输出回文串的最小长度

    解题思路:将给的字符串反过来成为一个新串,求这两个串的最长公共前后缀就行了

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<string>
    using namespace std;
    const int maxn=2e6+200;
    char s[maxn];
    char t[maxn];
    int _next[maxn];
    int tlen,n,slen;
    void get_next()
    {
        int j,k;//k代表的是相同字符的长度;
        j=0;k=-1;_next[0]=-1;
        while(j<tlen)//计算模式串的next数组,也就是每个字符若是匹配失败,该跳的位置;
        {
            if(k==-1||t[j]==t[k])//如果相等等于之前的+1;
                _next[++j]=++k;
            else
                k=_next[k];//如果不相等,跳转到k=next[k]去;把指针转移到之前的相同串去,保证最大前缀
        }
    }
    int kmp_pos()
    {
        int i=0,j=0;
        get_next();
        while(i<slen&&j<tlen)
        {
            if(j==-1||s[i]==t[j])//如果匹配没出问题,直接匹配
            {
                i++;j++;
            }
            else//如果匹配出现了问题,那么直接跳转到next[j]来,因为next[j]等于当前最长的公共前后缀,所以在公共后缀前面的那一部分没必要匹配了;
                j=_next[j];
        }
        return slen*2-j;
    }
    int main()
    {
        int tt;
        int cot=0;
        scanf("%d",&tt);
        while(tt--)
        {
            scanf("%s",s);
            cot++;
            int cnt=0;
            slen=strlen(s);
            for(int i=slen-1;i>=0;i--)
            {
                t[cnt++]=s[i];
            }
            tlen=cnt;
        cout<<"Case "<<cot<<": ";
           cout<<kmp_pos()<<endl;
        }
    }

    O - Unlucky Strings

     LightOJ - 1268 

    题意:给你一个合法字符集,一个长度len,一个字符串z,问你字符串长度为len且由合法字符组成且不包括字符串z的所有字符串的数量

    解题思路:首先要确定是矩阵构造的题目,构造一个矩阵ans【i】【j】,枚举当前正在匹配的字符的位置i,然后枚举字符集中的所有字符c,这一步代表的含义就是匹配到第i个位置时遇到字符c 要跳到哪个位置j,然后将ans[i][j]++,然后就是矩阵快速幂

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=55;
    char s[maxn],t[maxn];
    ll n,tlen,slen;
    ll _next[maxn];
    struct Matrix
    {
        unsigned m[maxn][maxn];
        Matrix()
        {
            memset(m,0,sizeof(m));
        }
        void init()
        {
            for(int i=0; i<maxn; i++)
                for(int j=0; j<maxn; j++)
                    m[i][j]=(i==j);
        }
        Matrix  operator +(const Matrix &b)const
        {
            Matrix c;
            for(int i=0; i<maxn; i++)
            {
                for(int j=0; j<maxn; j++)
                {
                    c.m[i][j]=(m[i][j]+b.m[i][j]);
                }
            }
            return c;
        }
        Matrix  operator *(const Matrix &b)const
        {
            Matrix c;
            for(int i=0; i<maxn; i++)
            {
                for(int j=0; j<maxn; j++)
                {
                    for(int k=0; k<maxn; k++)
                    {
                        c.m[i][j]=(c.m[i][j]+(m[i][k]*b.m[k][j]));
                    }
                }
            }
            return c;
        }
        Matrix  operator^(const ll &t)const
        {
            Matrix ans,a=(*this);
            ans.init();
            ll n=t;
            while(n)
            {
                if(n&1) ans=ans*a;
                a=a*a;
                n>>=1;
            }
            return ans;
        }
    };
    void get_next()
    {
        int j=0,k=-1;_next[0]=-1;
        while(j<tlen)
        {
            if(k==-1||t[j]==t[k])
                _next[++j]=++k;
            else
                k=_next[k];
        }
    }
    int main()
    {
        int tt;int cot=0;
        scanf("%d",&tt);
        while(tt--)
        {
            cot++;
            scanf("%lld",&n);
            scanf("%s%s",s,t);
            tlen=strlen(t);
            slen=strlen(s);
            get_next();
            Matrix a;
            for(int i=0;i<tlen;i++)
            {
                for(int j=0;j<slen;j++)
                {
                    int tmp=i;
                    while(tmp&&t[tmp]!=s[j])
                        tmp=_next[tmp];
                    if(t[tmp]==s[j])
                        tmp++;
                    a.m[i][tmp]++;
                }
            }
           /* for(int i=0;i<=tlen;i++)
            {
                for(int j=0;j<=tlen;j++)
                {
                    cout<<a.m[i][j]<<" ";
                }
                cout<<endl;
            }*/
            a=a^n;
            unsigned ans=0;
            for(int i=0;i<tlen;i++)
                ans+=a.m[0][i];
            cout<<"Case "<<cot<<": ";
            cout<<ans<<endl;
        }
    }
  • 相关阅读:
    Ubuntu(Linux) + mono + jexus +asp.net MVC3 部署
    爬虫代理
    爬取文件时,对已经操作过的URL进行过滤
    Scrapy项目创建以及目录详情
    Scrapy 框架 安装
    爬虫案例
    爬虫基础以及 re,BeatifulSoup,requests模块使用
    Django_Admin操作
    django 权限管理permission
    Node--01
  • 原文地址:https://www.cnblogs.com/huangdao/p/10809184.html
Copyright © 2011-2022 走看看