kmp

学习文档:http://www.cnblogs.com/c-cloud/p/3224788.html

1.Number Sequence

题意:给T组数据,每组有长度为n和m的母串和模式串。判断模式串是否是母串的子串,如果是输出最先匹配完成的位置,否则输出-1.

#include<iostream>
#include<cstdio>
using namespace std;
const int N=1000003;
int t[N],p[N],i,n,m,ne[N],T;
int read(){
    char c;int x=0,f=1;
    do{c=getchar();if(c=='-')f=-1;}while(c<48||c>57);
    do x=(x<<1)+(x<<3)+(c^48),c=getchar();while(c>=48&&c<=57);
    return f*x;
}
void make(){
    for (int i=1,j=0;i<m;i++){
        while (j && p[i]!=p[j]) j=ne[j-1];
        if (p[i]==p[j]) j++;
        ne[i]=j;
    }
}
int kmp(){
    make();
    for (int i=0,j=0;i<n;i++){
        while (j && t[i]!=p[j]) j=ne[j-1];
        if (t[i]==p[j]) j++;
        if (j==m) return i-m+2;
    }
    return -1;
}
int main(){
    scanf("%d",&T);
    while (T--){
        n=read();m=read();
        for (i=0;i<n;i++) t[i]=read();
        for (i=0;i<m;i++) p[i]=read();
        printf("%d\n",kmp());
    }
}

2. Oulipo

题意:给T组数据,每组有两个字符串按顺序分别为模式串和母串。判断模式串在母串中出现的次数。模式串在母串中是可以相互覆盖的。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1000003,M=10003;
int ne[M],T,n,m;
char p[M],t[N];
void make(){
    for (int i=1,j=0;i<m;i++){
        while (j && p[i]!=p[j]) j=ne[j-1];
        if (p[i]==p[j]) j++;
        ne[i]=j;
    }
}
int kmp(){
    make();
    int sum=0;
    for (int i=0,j=0;i<n;i++){
        while (j && t[i]!=p[j]) j=ne[j-1];
        if (t[i]==p[j]) j++;
        if (j==m) sum++;
    }
    return sum;
}
int main(){
    scanf("%d",&T);
    while (T--){
        scanf("%s%s",p,t);
        n=strlen(t);m=strlen(p);
        printf("%d\n",kmp());
    }
}

3.剪花布条

题意:输入母串和模式串,以’#‘为结束。剪纸花,从母串中减去模式串问能剪出多少。这就意味着求解模式串的数量时不能重叠覆盖

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1003;
int ne[N],T,n,m;
char p[N],t[N];
void make(){
    for (int i=1,j=0;i<m;i++){
        while (j && p[i]!=p[j]) j=ne[j-1];
        if (p[i]==p[j]) j++;
        ne[i]=j;
    }
}
int kmp(){
    make();
    int sum=0;
    for (int i=0,j=0;i<n;i++){
        while (j && t[i]!=p[j]) j=ne[j-1];
        if (t[i]==p[j]) j++;
        if (j==m) sum++,j=0;
    }
    return sum;
}
int main(){
    while (~scanf("%s",t)){
        if (t[0]=='#') return 0;
        scanf("%s",p);
        n=strlen(t);m=strlen(p);
        printf("%d\n",kmp());
    }
}

4.Cyclic Nacklace

题意:给T组数据,每组有一个字符串,只能在字符串的前面和后面增加字符,不能再中间增加,求要使这个字符串是周期循环的且周期的次数大于一,至少需要增加的字符数量。注意这个字符串是个手链,也就是说是增加字符后首位相连是周期的即可

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=100003;
int T,n,i,j,ne[N],t;
char s[N];
int main(){
    scanf("%d",&T);
    while (T--){
        scanf("%s",s);
        n=strlen(s);
        for (i=1,j=0;i<n;i++){
            while (j && s[i]!=s[j]) j=ne[j-1];
            if (s[i]==s[j]) j++;
            ne[i]=j;
        }
        if (!ne[n-1]){
            printf("%d\n",n);
            continue;
        }
        t=n-ne[n-1];
        printf("%d\n",n%t==0?0:t-n%t);
    }
}

5.Period

题意:给字符串的长度和一个字符串。读到eof。求每个字符串中在i之前的位置是循环的且次数大于1,求这个位置i以及循环的次数

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1000003;
int t,n,ne[N],i,j,T;
char s[N];
int main(){
    while (1){
        scanf("%d",&n);
        if (!n) return 0;
        printf("Test case #%d\n",++T);
        scanf("%s",s);
        for (i=1,j=0;i<n;i++){
            while (j && s[i]!=s[j]) j=ne[j-1];
            if (s[i]==s[j]) j++;
            ne[i]=j;
            t=i+1-ne[i];
            if ((i+1)%t==0 && i+1>t) printf("%d %d\n",i+1,(i+1)/t);
        }
        putchar('\n');
    }
}

6.power strings

题意:每组给以个字符串,一直读到’.’.字符串s = a^n,及都是由a构成的,求n的值
做法:求最小循环节,如果整除,那除得的数及为ans。如果不整除ans = 1

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=1000003;
int n,i,j,ne[N],t;
char s[N];
int main(){
    while (1){
        scanf("%s",s);
        if (s[0]=='.') return 0;
        n=strlen(s);
        for (i=1,j=0;i<n;i++){
            while (j && s[i]!=s[j]) j=ne[j-1];
            if (s[i]==s[j]) j++;
            ne[i]=j;
        }
        t=n-ne[n-1];
        printf("%d\n",n%t==0?n/t:1);
    }
}

7.Seek the Name, Seek the Fame

题意:每组一个字符串,读到eof结束。寻找i使得字符串的前缀等于后缀

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=400003;
int ne[N],m,i,ans[N],cnt,t;
char s[N];
void make(){
    for (int i=1,j=0;i<m;i++){
        while (j && s[i]!=s[j]) j=ne[j-1];
        if (s[i]==s[j]) j++;
        ne[i]=j;
    }
}
int main(){
    while (~scanf("%s",s)){
        m=strlen(s);
        make();
        cnt=0;t=ne[m-1];
        while (t){
            ans[cnt++]=t;
            t=ne[t-1];
        }
        for (i=cnt-1;i>=0;i--) printf("%d ",ans[i]);
        printf("%d\n",m);
    }
}

8.Blue Jeans

题意:T组数据,每组m个DNA序列,每个DNA序列都有60个字符,且只由ACGT几个字母构成。判断m个DNA序列最长公共的子串是什么?如果有相同长度的公共子串,则输出字典序最小的。如果小于3输出“no ……”,大于等于3输出字符串

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=61,M=1802;
int vis[M],i,j,n,m,ne[M][N],cnt,k,T,l[M];
char s1[N],s[M][N];
bool cmp(int x,int y){
    if (l[x]!=l[y]) return l[x]>l[y];
    for (int i=0;i<l[x];i++)
        if (s[x][i]!=s[y][i]) return s[x][i]<s[y][i];
}
void make(int t){
    for (int i=1,j=0;i<l[t];i++){
        while (j && s[t][i]!=s[t][j]) j=ne[t][j-1];
        if (s[t][i]==s[t][j]) j++;
        ne[t][i]=j;
    }
}
int kmp(int t){
    int n=strlen(s1);
    if (l[t]>n) return 1;
    for (int i=0,j=0;i<n;i++){
        while (j && s[t][j]!=s1[i]) j=ne[t][j-1];
        if (s[t][j]==s1[i]) j++;
        if (j==l[t]) return 0;
    }
    return 1;
}
int main(){
    scanf("%d",&T);
    while (T--){
        scanf("%d%s",&m,s1);
        n=strlen(s1);
        memset(vis,0,sizeof(vis));
        memset(s,0,sizeof(s));
        cnt=0;
        for (i=0;i<n;i++)
            for (j=i+2;j<n;j++){
                for (k=i;k<=j;k++) s[cnt][k-i]=s1[k];
                l[cnt]=j-i+1;
                make(cnt);cnt++;
            }
        for (i=1;i<m;i++){
            scanf("%s",s1);
            for (j=0;j<cnt;j++)
                if (!vis[j]) vis[j]=kmp(j);
        }
        k=-1;
        for (i=0;i<cnt;i++)
            if (!vis[i] && (k==-1 || cmp(i,k))) k=i;
        printf("%s\n",k!=-1?s[k]:"no significant commonalities");
    }
}

9.Simpsons’ Hidden Talents

题意:每组给两个字符串以eof结尾。求s1的前缀,等于s2后缀的长度.如果长度不是零空格之后输出相同的部分,否则只输出零即可

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=50003;
int ne[N],i,l,n,m;
char s1[N],s2[N];
void make(){
    for (int i=0,j=1;j<m;j++){
        while (i && s1[i]!=s1[j]) i=ne[i-1];
        if (s1[i]==s1[j]) i++;
        ne[j]=i;
    }
}
int kmp(){
    make();
    int i=0,j=0;
    for (;j<m;j++){
        while (i && s1[i]!=s2[j]) i=ne[i-1];
        if (s1[i]==s2[j]) i++;
    }
    return i;
}
int main(){
    while (~scanf("%s",s1)){
        scanf("%s",s2);
        n=strlen(s1);m=strlen(s2);
        l=kmp();
        for (i=0;i<l;i++) putchar(s1[i]);
        if (l) putchar(' ');
        printf("%d\n",l);
    }
}

10.Count the string

题意:给T组数据,每组数据给一个长度为n的字符串s。求字符串每个前缀出现的次数,结果mod 10007

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=200003;
int T,n,i,sum,f[N],ne[N],j;
char s[N];
int main(){
    scanf("%d",&T);
    while (T--){
        scanf("%d%s",&n,s);
        for (i=1,j=0;i<n;i++){
            while (j && s[i]!=s[j]) j=ne[j-1];
            if (s[i]==s[j]) j++;
            ne[i]=j;
        }
        f[0]=0;sum=0;
        for (i=0;i<n;i++){
            f[i+1]=f[ne[i]]+1;
            sum+=f[i+1];
        }
        printf("%d\n",sum%10007);
    }
}

11.Clairewd’s message

题意:给T组数据,每组数据第一行是26个字母表示[a,z]所对应的密文字母。第二行的字符串由两部分组成,第一部分是密文部分,第二部分是明文部分。明文部分可能是不完整的,也可能是完整的输出完整的明文部分

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=100003;
int ne[N],i,j,ans,T,l;
char str[28],s1[N],s2[N];
void make(char *s){
    int n=strlen(s);
    for (int i=1,j=0;i<n;i++){
        while (j && s[i]!=s[j]) j=ne[j];
        if (s[i]==s[j]) j++;
        ne[i]=j;
    }
}
int kmp(char *s,char *t){
    make(t);
    int n=strlen(s),i=0,j=0;
    for (;i<n;i++){
        while (j && s[i]!=t[j]) j=ne[j];
        if (s[i]==t[j]) j++;
    }
    return j;
}
int main(){
    scanf("%d",&T);
    while (T--){
        scanf("%s%s",str,s1);
        printf("%s",s1);
        l=strlen(s1);
        strcpy(s2,s1+(l+1)/2);
        for (i=0;s1[i];i++)
            for (j=0;j<26;j++)
                if (s1[i]==str[j]){
                    s1[i]='a'+j;
                    break;
                }
        ans=kmp(s2,s1);
        for (i=ans;i<l-ans;i++) putchar(s1[i]);
        putchar('\n');
    }
}

12. Period II

题意:每组n个字符串,以eof结束。求每个字符串中满足S[i]=S[i+P] for i in [0..SIZE(S)-p-1],的位置。

#include<cstdio>
#include<cstring>
const int N=1000003;
int Case,T,l,i,j,t,ne[N],ans[N],cnt;
char s[N],c;
int main(){
    scanf("%d",&T);
    while (T--){
        scanf("%s",s);
        l=strlen(s);
        for (i=1,j=0;i<l;i++){
            while (j && s[i]!=s[j]) j=ne[j-1];
            if (s[i]==s[j]) j++;
            ne[i]=j;
        }
        t=ne[l-1];cnt=0;
        while (t){
            ans[cnt++]=l-t;
            t=ne[t-1];
        }
        printf("Case #%d: %d\n",++Case,cnt+1);
        for (i=0;i<cnt;i++) printf("%d ",ans[i]);
        printf("%d\n",l);
    }
}

13.Theme Section

题意:n个字符串,每个字符串都可以写成EAEBE的形式,其中E可以为空,寻找最长的E

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=1000003;
int T,l,ne[N];
char s[N];
void make(){
    for (int i=1,j=0;i<l;i++){
        while (j && s[i]!=s[j]) j=ne[j-1];
        if (s[i]==s[j]) j++;
        ne[i]=j;
    }
}
int kmp(){
    make();
    for (int i=ne[l-1];i;i=ne[i-1])
        for (int j=i<<1;j<=l-i;j++)
            if (ne[j-1]==i) return i;
    return 0;
}
int main(){
    scanf("%d",&T);
    while (T--){
        scanf("%s",s);
        l=strlen(s);
        printf("%d\n",kmp());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值