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\n",&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\n");
        else
        {
            for(int i=0;i<ans;i++)
                printf("%c",char_ans[i]);
            printf("\n");
        }
    }
}

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;
    }
}

猜你喜欢

转载自www.cnblogs.com/huangdao/p/10809184.html