10.22 kmp练习

虽然noip很少有单独把一些关于字符串的算法拉出来考,但是一定的练习也是必要的23333333333,至少要把板子打一遍吧2333333333333

这些题是一个裸到不能再裸的kmp,算是开始?233333

【hdu1711】Number Sequence

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int ne[10010],n,m,t,ans;
int a[1000010],b[10010];
inline void init()
{
    int j=0;//j是指当前在匹配串的第几位,预处理next数组实际上很像next数组自己进行匹配 
    for(int i=2;i<=m;i++)//i是指当前在被匹配串的第几位 
    {
        while(j&&b[i]!=b[j+1])//如果当前这一位 
            j=ne[j];//向前面的与这一段匹配的子串跳转而去 
        if(b[i]==b[j+1])//如果当前这一位匹配 
            j++;//j就标记在这里 
        ne[i]=j;//当前这位的next就记录为j 
    }
}
//kmp算法实际上是记录了之前的匹配信息,在这个基础上进行下一步匹配,感觉和记忆化搜索有点像233333 
inline void kmp()//和刚才预处理类似 
{
    int j=0;ans=0;//多加了个ans 
    for(int i=1;i<=n;i++)
    {
        while(j&&b[j+1]!=a[i])//这里a成了被匹配串 
            j=ne[j];
        if(a[i]==b[j+1])
            j++;
        if(j==m)//因为这个题说找到最小的一个k,所以在这里停下 
        {
            ans=i-j+1;return;
        }
    }
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        memset(ne,0,sizeof(ne));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=m;i++)
            scanf("%d",&b[i]);
        init();//预处理 
        kmp();
        if(ans>0)
            printf("%d\n",ans);
        else
            printf("-1\n");
    }
}

 【hdu1686】Oulipo 

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int t,lena,lenb,ne[10010],ans;
char a[10010],b[1000010];
inline void init()
{
    int j=0;
    for(int i=2;i<=lena;i++)
    {
        while(j&&a[i]!=a[j+1])
            j=ne[j];
        if(a[i]==a[j+1])
            j++;
        ne[i]=j;
    }
}
inline void kmp()
{
    int j=0;ans=0;
    for(int i=1;i<=lenb;i++)
    {
        while(j&&a[j+1]!=b[i])
            j=ne[j];
        if(b[i]==a[j+1])
            j++;
        if(j==lena)
            ans++,j=ne[j];//和刚才那个题最大的变化就是这里,从直接返回到继续查找并答案加1 
    }
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s%s",a+1,b+1);
        memset(ne,0,sizeof(ne));
        lena=strlen(a+1),lenb=strlen(b+1);//这种情况括号里面记得+1!!!!! 
        init();
        kmp();
        printf("%d\n",ans);
    }
}

 【hdu2087】剪花布条

这个题还是换汤不换药……

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int t,lena,lenb,ne[10010],ans;
char a[10010],b[1000010];
inline void init()
{
    int j=0;
    for(int i=2;i<=lenb;i++)
    {
        while(j&&b[i]!=b[j+1])
            j=ne[j];
        if(b[i]==b[j+1])
            j++;
        ne[i]=j;
    }
}
inline void kmp()
{
    int j=0;ans=0;
    for(int i=1;i<=lena;i++)
    {
        while(j&&b[j+1]!=a[i])
            j=ne[j];
        if(a[i]==b[j+1])
            j++;
        if(j==lenb)
            ans++,j=0;//这个题就是把这里j清零就好,因为以前的部分不能用了 
    }
}
int main()
{
    while(~scanf("%s",a+1))
    {
        if(a[1]=='#')
            break;
        scanf("%s",b+1);
        memset(ne,0,sizeof(ne));
        lena=strlen(a+1),lenb=strlen(b+1);//这种情况括号里面记得+1!!!!! 
        init();
        kmp();
        printf("%d\n",ans);
    }
}

【hdu3746】Cyclic Nacklace

严重吐槽这个题面描述不到位

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int t,lena,ne[100010],ans,lenb;
char a[100010];
inline void init()//只用求这个字符串的next数组就行了 
{
    int j=0;
    for(int i=2;i<=lena;i++)
    {
        while(j&&a[i]!=a[j+1])
            j=ne[j];
        if(a[i]==a[j+1])
            j++;
        ne[i]=j;
    }
}
inline void cha()//它好像数据要求如果现在恰好不循环,则认为现在只有一个循环节(无论他是否有已经有好几个小循环)
//所以我一直wa,虽然他只说循环节必须多于一个,这个题好坑啊 
{
    ans=0,lenb=1;
    int xun=lena-ne[lena];//寻找一下上一个循环节的位置 
    if(ne[lena]==0)//如果到最后还是0,则说明这整个是个循环节 
        ans=lena;
    else if(lena%xun==0)//如果恰好循环就答案为0 
        ans=0;
    else//否则就得凑 
        ans=xun-(lena%xun);
}
int main()
{
    scanf("%d",&t);
    for(int i=1;i<=t;i++)
    {
        scanf("%s",a+1);
        memset(ne,0,sizeof(ne));
        lena=strlen(a+1);
        init();
        cha();
        printf("%d\n",ans);
    }
}

 

posted @ 2017-10-22 15:05  那一抹落日的橙  阅读(210)  评论(0编辑  收藏  举报