HDU 2594 EX_KMP或者字符串hash

来源:互联网 发布:java简历工作内容 编辑:程序博客网 时间:2024/06/05 02:47

题意:给你2个字符串a , b 。问 a的前缀和b的后缀的公共部分最长是多少。

思路:把a从前往后hash,把b从后往前hash,如果hash值相等,那么代表两个字符串相等,那么更新长度。

最后输出这个长度的最大值即可。

还可以用EX_KMP搞,我们可以把两个字符串连成一个,然后根据EX_KMP的NEXT数组的作用,直接就可以判断后缀是否等于前缀。

先来一发HASH的代码。

#include <set>#include <map>#include <stack>#include <cmath>#include <queue>#include <cstdio>#include <string>#include <vector>#include <iomanip>#include <cstring>#include <iostream>#include <algorithm>#define Max 2505#define FI first#define SE second#define ll long long#define PI acos(-1.0)#define inf 0x7fffffff#define LL(x) ( x << 1 )#define bug puts("here")#define PII pair<int,int>#define RR(x) ( x << 1 | 1 )#define mp(a,b) make_pair(a,b)#define mem(a,b) memset(a,b,sizeof(a))#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )using namespace std;#define uint unsigned int#define N 55555char a[N] , b[N] ;int main() {    while(scanf("%s%s",a,b) != EOF){        int la = strlen(a) ;int lb = strlen(b) ;        uint seed = 31 , hasha = 0 , hashb = 0 , Hx = 1 ;        int posa = 0 , posb = lb - 1 ;        int ans = -1 ;        while(posa < la && posb >= 0){            hasha = hasha * seed + a[posa] ;            hashb = hashb + Hx * b[posb] ;            hasha &= inf ;            hashb &= inf ;            if(hasha == hashb)ans = posa + 1 ;            Hx *= seed ;            posa ++ ;            posb -- ;        }        for (int i = 0 ; i < ans ; i ++ )cout << a[i] ;        if(ans == -1)cout << 0 << endl;        else cout<< " " << ans << endl;    }    return 0;}
再来一发EX_KMP的代码。

#include <set>#include <map>#include <stack>#include <cmath>#include <queue>#include <cstdio>#include <string>#include <vector>#include <iomanip>#include <cstring>#include <iostream>#include <algorithm>#define Max 2505#define FI first#define SE second#define ll long long#define PI acos(-1.0)#define inf 0x3fffffff#define LL(x) ( x << 1 )#define bug puts("here")#define PII pair<int,int>#define RR(x) ( x << 1 | 1 )#define mp(a,b) make_pair(a,b)#define mem(a,b) memset(a,b,sizeof(a))#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )using namespace std;#define N 111111int Next[N] ;char b[N] ;void EX_Next(){    int x = 0 ;    int l = strlen(b) ;    Next[0] = l ;    while(x < l - 1 && b[x] == b[x + 1])x ++ ;    Next[1] = x ;    x = 1 ;    for (int k = 2 ; k < l ; k ++ ){        int p = x + Next[x] - 1 , L = Next[k - x] ;        if(k - 1 + L >= p){            int j = (p - k + 1) > 0 ? (p - k + 1) : 0 ;            while(k + j < l && b[k + j] == b[j]) j ++ ;            Next[k] = j ;            x = k ;        }else {            Next[k] = L ;        }    }}int main() {    while(scanf("%s",b) != EOF){        int l = strlen(b) ;        scanf("%s",b + l) ;        EX_Next() ;        int l1 = strlen(b) ;int ans = -1 ;        for (int i = l ; i < l1 ; i ++ ){            int now = Next[i] ;            if(i + now == l1)                ans = max(ans , now ) ;        }        ans = ans >= l ? l : ans ;        for (int i = 0 ; i < ans ; i ++ )cout << b[i] ;        if(ans == -1)cout << 0 << endl ;        else cout << " " << ans << endl;    }    return 0;}

HDU 1867 同样的意思,给定两个字符串,找出一个串的前缀和一个串的后缀的最大重复字串,然后将两个串合起来,当然重叠部分算一次,然后输出最后的串。

注意的是这道题两个字符串哪个在前那个在后不知道,所有做两次EX_KMP,分别求出各串最为前缀和后缀能匹配的最大长度,最后输出长度小字典序小的那个即可。

#include <set>#include <map>#include <stack>#include <cmath>#include <queue>#include <cstdio>#include <string>#include <vector>#include <iomanip>#include <cstring>#include <iostream>#include <algorithm>#define Max 2505#define FI first#define SE second#define ll long long#define PI acos(-1.0)#define inf 0x3fffffff#define LL(x) ( x << 1 )#define bug puts("here")#define PII pair<int,int>#define RR(x) ( x << 1 | 1 )#define mp(a,b) make_pair(a,b)#define mem(a,b) memset(a,b,sizeof(a))#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )using namespace std;#define N 211111int Next[N] ;void EX_NEXT(char *a) {    int l = strlen(a) ;    int x = 0 ;    Next[0] = l ;    while(x < l - 1 && a[x] == a[x + 1]) x ++ ;    Next[1] = x ;    x = 1 ;    for (int k = 2 ; k < l ; k ++ ) {        int p = x + Next[x] - 1 , L = Next[k - x] ;        if(k - 1 + L >= p) {            int j = (p - k + 1) > 0 ? (p - k + 1 ) : 0 ;            while(k + j < l && a[k + j] == a[j]) j ++ ;            Next[k] = j ;            x = k ;        } else  Next[k] = L ;    }}string gao(char *x , char *y){    int l1 = strlen(x) , l = l1 , posy = 0 ;    while(y[posy])x[l ++ ] = y[posy ++ ] ;    x[l] = '\0' ;EX_NEXT(x) ;int l2 = strlen(x) ;int num = 0 ;    for (int i = l1 ; i < l2 ; i ++ )        if(i + Next[i] == l2)num = max(num , Next[i]) ;    string ff = y ;    while(x[num] && num < l1)ff += x[num ++] ;    return ff ;}char a[N] , b[N] ;char x[N] , y[N] ;string check(string ans , string tans){    if(ans.size() > tans.size())return tans ;    if(ans.size() < tans.size())return ans ;    return ans > tans ?  tans : ans ;}int main() {    while(scanf("%s%s",b,a) != EOF) {        strcpy(x , a) ;strcpy(y , b) ;        printf("%s\n",check(gao(a , b) , gao(y , x)).c_str()) ;    }    return 0 ;}




原创粉丝点击