hdu 1867 A + B for you again

Generally speaking, there are a lot of problems about strings processing. Now you encounter another such problem. If you get two strings, such as “asdf” and “sdfg”, the result of the addition between them is “asdfg”, for “sdf” is the tail substring of “asdf” and the head substring of the “sdfg” . However, the result comes as “asdfghjk”, when you have to add “asdf” and “ghjk” and guarantee the shortest string first, then the minimum lexicographic second, the same rules for other additions.

InputFor each case, there are two strings (the chars selected just form ‘a’ to ‘z’) for you, and each length of theirs won’t exceed 10^5 and won’t be empty.OutputPrint the ultimate string by the book.Sample Input
asdf sdfg
asdf ghjk
Sample Output
asdfg
asdfghjk

合并字符串,两串a,b,a的后缀和b的前缀最大匹配长度为d,b的后缀和a的前缀的最大匹配长度为e,哪个长度大,就怎么衔接,否则按字母顺序衔接。
kmp找两个长度。
代码:
#include <stdio.h>
#include <string.h>
#define MAX 100005
char a[MAX],b[MAX];
int Next[MAX];
void getNext(int n,char *s) {
    int i = 0,j = -1;
    Next[i] = -1;
    while(i < n) {
        if(j == -1 || s[j] == s[i]) {
            Next[++ i] = ++ j;
        }
        else j = Next[j];
    }
}
int kmp(char *p,char *q) {
    int n = strlen(p),m = strlen(q);
    getNext(m,q);
    int i = -1,j = -1;
    while(i < n) {
        if(j == -1 || p[i] == q[j]) {
            i ++;j ++;
        }
        else j = Next[j];
    }
    return j;
}
int main() {
    while(~scanf("%s%s",a,b)) {
        int d = kmp(a,b),e = kmp(b,a);///保存a后缀和b前缀的最大重叠 以及 反过来 比较哪个大 就重叠那个 按相应顺序输出,如果相等就按字典序
        if(d > e) printf("%s%s",a,b + d);
        else if(d < e) printf("%s%s",b,a + e);
        else {
            if(strcmp(a,b) > 0)printf("%s%s",b,a + e);
            else printf("%s%s",a,b + d);
        }
        putchar('\n');
    }
}

也可以组合求Next。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define MAX 100005
using namespace std;
char a[MAX],b[MAX],s[MAX * 2];
int Next[MAX * 2],m;
int getNext(char *p,char *q) {
    strcpy(s,p);
    strcat(s,q);
    int i = 0,j = -1;
    Next[i] = -1;
    while(s[i]) {
        if(j == -1 || s[j] == s[i]) {
            Next[++ i] = ++ j;
        }
        else j = Next[j];
    }
    int  c = strlen(s);
    while(Next[c] > m) c = Next[c];
    return Next[c];
}
int main() {
    while(~scanf("%s%s",a,b)) {
        m = min(strlen(a),strlen(b));
        int d = getNext(b,a),e = getNext(a,b);///保存a后缀和b前缀的最大重叠 以及 反过来 比较哪个大 就重叠那个 按相应顺序输出,如果相等就按字典序
        if(d > e) printf("%s%s",a,b + d);
        else if(d < e) printf("%s%s",b,a + e);
        else {
            if(strcmp(a,b) > 0)printf("%s%s",b,a + e);
            else printf("%s%s",a,b + d);
        }
        putchar('\n');
    }
}

当然 也可以用扩展kmp

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define MAX 100005
using namespace std;
char a[MAX],b[MAX];
int Next[MAX],Prefix[MAX];
void getNext(char *str) {///获得Next数组
    int p = 1;///匹配最远的开始匹配位置 比如从i开始和0位置依次往后匹配相等能到最远的位置 p就是i 即i + Next[i] - 1最大时的i为p
    Next[0] = strlen(str);///显然自己和自己匹配
    Next[1] = 0;
    while(str[Next[1] + 1] && str[Next[1] + 1] == str[Next[1]]) Next[1] ++;///匹配1位置作为基础
    for(int i = 2;str[i];i ++) {///2位置开始
        if(i + Next[i - p] < p + Next[p]) Next[i] = Next[i - p];///如果不超过最远位置
        else {///超过最远位置
            if(p + Next[p] - 1 >= i) Next[i] = p + Next[p] - i;///i点没超过最远位置 实际是 p + Next[p] - 1 - i + 1
            else Next[i] = 0;///否则从头开始匹配啊
            while(str[Next[i] + i] && str[Next[i]] == str[Next[i] + i]) Next[i] ++;///继续匹配
            p = i;
        }
    }
}
int ExKmp(char *str1,char *str2) {
    getNext(str2);
    int p = 0,len = strlen(str1);
    Prefix[0] = 0;
    while(str1[Prefix[0]] && str2[Prefix[0]] && str1[Prefix[0]] == str2[Prefix[0]]) Prefix[0] ++;
    for(int i = 1;str1[i];i ++) {
        if(i + Next[i - p] < p + Prefix[p]) Prefix[i] = Next[i - p];///i加上i-p前缀长度 没超过最远位置
        else {
            if(i <= p + Prefix[p] - 1) Prefix[i] = p + Prefix[p] - i;///i没超过最远位置
            else Prefix[i] = 0;
            while(str1[i + Prefix[i]] && str1[i + Prefix[i]] == str2[Prefix[i]]) Prefix[i] ++;///继续匹配
            p = i;///更新最远位置下标
        }
    }
    for(int i = 0;i < len;i ++) {
        if(i + Prefix[i] == len) return Prefix[i];
    }
    return 0;
}
int main() {
    while(~scanf("%s%s",a,b)) {
        int d = ExKmp(a,b),e = ExKmp(b,a);///保存a后缀和b前缀的最大重叠 以及 反过来 比较哪个大 就重叠那个 按相应顺序输出,如果相等就按字典序
        if(d > e) printf("%s%s",a,b + d);
        else if(d < e) printf("%s%s",b,a + e);
        else {
            if(strcmp(a,b) > 0)printf("%s%s",b,a + e);
            else printf("%s%s",a,b + d);
        }
        putchar('\n');
    }
}

 再次复习扩展kmp

#include <iostream>
#include <cstdio>
#include <cstring>
#define MAX 100005
using namespace std;

void getNext(char *str,int *Next) {
    int p = 1;
    while(str[1 + Next[1]] && str[1 + Next[1]] == str[Next[1]]) Next[1] ++;
    for(int i = 2;str[i];i ++) {
        if(i + Next[i - p] < p + Next[p]) Next[i] = Next[i - p];
        else {
            if(i <= p + Next[p] - 1) Next[i] = p + Next[p] - i;
            else Next[i] = 0;
            while(str[i + Next[i]] && str[i + Next[i]] == str[Next[i]]) Next[i] ++;
            p = i;
        }
    }
}
int ExKmp(char *s,char *t) {
    int Next[MAX] = {0},Prefix[MAX] = {0};
    getNext(t,Next);
    int p = 0;
    while(s[0 + Prefix[0]] && s[0 + Prefix[0]] == t[Prefix[0]]) Prefix[0] ++;
    for(int i = 1;s[i];i ++) {
        if(i + Next[i - p] < p + Prefix[p]) Prefix[i] = Next[i - p];
        else {
            if(i < p + Prefix[p]) Prefix[i] = p + Prefix[p] - i;
            else Prefix[i] = 0;
            while(s[i + Prefix[i]] && s[i + Prefix[i]] == t[Prefix[i]]) Prefix[i] ++;
            if(i + Prefix[i] > p + Prefix[p]) p = i;///不加这一步 最后返回的就不对,  比如 aaaa aaa 应输出 aaaa
        }
    }
    return p + Prefix[p] < strlen(s) ? 0 : Prefix[p];
}
int main() {
    char a[MAX],b[MAX];
    while(~scanf("%s%s",a,b)) {
        int d = ExKmp(a,b),e = ExKmp(b,a);
        if(d > e) printf("%s%s",a,b + d);
        else if(d < e) printf("%s%s",b,a + e);
        else {
            if(strcmp(a,b) > 0)printf("%s%s",b,a + e);
            else printf("%s%s",a,b + d);
        }
        putchar('\n');
    }
}

 

转载于:https://www.cnblogs.com/8023spz/p/7795862.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值