zoukankan      html  css  js  c++  java
  • HihoCoder1084: 扩展KMP(二分+hash,求T串中S串的数量,可以失配一定次数)

    zz:https://www.cnblogs.com/hua-dong/p/8524787.html

    时间限制:4000ms
    单点时限:4000ms
    内存限制:256MB

    你知道KMP吗?它是用于判断一个字符串是否是另一个字符串的子串的算法。今天我们想去扩展它。

    在信息理论中,在两个相同长度的字符串之间的海明码距离是:两个字符串相同位置对应的字符不同的位置数目。换种说法,它表示将一个字符串转化为另一个字符串所需要改变字符的最小数目。

    下面这些字符串之间的海明码距离:

    "karolin"和"kathrin"是3.

    "karolin"和"kerstin"是3.

    1011101和1001001是2.

    2173896和2233796是3.

    现在给定两个字符串stra,strb,和一个整数k。对于stra中的一个子串,如果它的长度和strb的相同且它们之间的海明码距离不超过k,我们认为它们是匹配的。

    那么我们想知道在stra中有多少子串是和strb是匹配的。

    输入
    有多组测试(大约100),每个用例占3行。

    第一行是stra。

    第二行是strb。

    第三行是k。

    请处理到文件末尾。

    【参数说明】

    1<=stra,strb的长度<=100000

    stra,strb只包含小写字母

    0<=k<=5

    输出
    对于每个测试用例,以输出结果占一行。

    样例输入
    abcde
    f
    0
    abcde
    f
    1
    karolin
    kathrin
    3
    样例输出
    0
    5
    1
    题意:求T串中S串的数量,最多可以失配K。

    思路:len1=|S|,len2=|T|。枚举S的起点i,如果i后面的可行的长度>=len2,则累加1次。

    具体实现:二分得到当前最长匹配长度,假设是L,则跳过L后面一位(失配的一位),同时失配次数累加一次,继续检测后面的。 如果匹配成功,而且跳过次数不超过K次,则满足。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    #define ull unsigned long long
    const int maxn=100000;
    const int seed=131;
    char a[maxn+10],b[maxn+10];
    int hash1[maxn+10],hash2[maxn+10],g[maxn+10],K;
    int L1,L2,ans;
    int find(int w,int v)
    //字符串1从第w位开始,字符串2从第v位开始,它们能匹配多少字符 
    {
        int L=1,R=L2-v+1,res=0;
        while(L<=R)
    	{
            int Mid=(L+R)>>1;
            if(hash1[w+Mid-1]-hash1[w-1]*g[Mid]==hash2[v+Mid-1]-hash2[v-1]*g[Mid]) 
    		     res=Mid,L=Mid+1;
            else 
    		     R=Mid-1; 
        } return res;
    }
    bool check(int x)
    {
        int w=x,v=1;
        for(int i=1;i<=K;i++)
    	{
            int L=find(w,v);//至多能匹配L位
    		//则串1中第w+l位与串2中第v+l位是不匹配的 
            w=w+L+1; //下一次匹配的开始位置 
    		v=v+L+1; //同上 
            if(v>L2) return true;
        }
        int L=find(w,v);//下面这一段似乎也可以不用写的吧 
        w=w+L; v=v+L;
        if(v>L2) return true;
        return false;
    }
    int main()
    {
        g[0]=1;
        for(int i=1;i<=maxn;i++) 
    	    g[i]=g[i-1]*seed;
        while(~scanf("%s%s%d",a+1,b+1,&K))
    	{
            L1=strlen(a+1); 
    		L2=strlen(b+1); 
    		ans=0;
            for(int i=1;i<=L1;i++) 
    		    hash1[i]=hash1[i-1]*seed+a[i];
            for(int i=1;i<=L2;i++) 
    		    hash2[i]=hash2[i-1]*seed+b[i];
            for(int i=1;i<=L1-L2+1;i++) //枚举字符串1的开始位置 
               if(check(i))  
    		       ans++;
            printf("%d
    ",ans);
        }
        return 0;
    }
    

      

  • 相关阅读:
    Uva 10779 collector's problem
    poj 2728 最优比率树(最小生成树问题)
    LA 3126 二分图匹配 最小路径覆盖
    poj 1149 最大流构图
    Step By Step(Java XML篇)
    Step By Step(Java 输入输出篇)
    Step By Step(Java 集合篇)
    Step By Step(Java 线程篇)
    Step By Step(Java 反射篇)
    Step By Step(Java 国际化篇)
  • 原文地址:https://www.cnblogs.com/cutemush/p/12378120.html
Copyright © 2011-2022 走看看