Codeforces 25E 字符串hash模板题

题意

  • 三个字符串,问最短的把这三个字符串的作为子串的字符串长度。

思路

  • 三个字符串A(3,3)种排列方式,可以dfs,但是给定了三个,为方便起见,就手写了6种情况。
  • 先判断三个串互相有没有为子串的情况,作为子串的就可以不被考虑了。
  • 剩下的串,找前面串的后缀和后面串的前缀的最长公共部分。
  • 这可以完全用kmp解决,但是为了练习字符串hash,所以就这么写了~

实现

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <iostream>
#include <map>
using namespace std;
string str[3];
string strTmp;
int type[6][3] = {0,1,2,0,2,1,1,0,2,1,2,0,2,0,1,2,1,0};
typedef unsigned long long ull;
const int maxn = 100005;
//或者100000007,一般取奇数即可
//先用长度比较,再用2~3个hash来判断,本题不需要这么做~ 
const ull B = 9973;

const int inf = 0x3f3f3f3f;
//判断str1后缀和str2前缀相等的最大长度 
int cmp(string& str1,string& str2){
    int ret = 0;
    int len1 = str1.length();
    int len2 = str2.length();
    ull ah=0,bh=0,tmp=1;
    for (int i=0;i<min(len1,len2);i++){
        bh = bh * B + str2[i];
        ah = ah + str1[len1-i-1] * tmp;
        tmp *= B;
        if (bh == ah){
            ret = i+1;
        }
    }
    return ret;
}
//判断str2是否为str1的子串 
bool isInside(string& str1,string& str2){
    int len1 = str1.length();
    int len2 = str2.length();

    ull t= 1;
    for (int i=0;i<len2;i++)
        t*=B;
    ull ah = 0, bh = 0;
    for (int i=0;i<len2;i++){
        ah = ah * B + str2[i];
        bh = bh * B + str1[i];
    }
    if (ah == bh)
        return 1;
    for (int i=0; i+len2 < len1 ;i++){
        bh = bh * B + str1[i + len2] - str1[i] * t;
        if (ah == bh)
            return 1;
    }
    return 0;
}


int main(){
    for (int i=0;i<3;i++)
        cin>>str[i];
    int ans = inf;
    for (int i=0;i<6;i++){
        int tmp = str[type[i][0]].length();
        strTmp = str[type[i][0]];
        for (int j=0;j<2;j++){
            if (str[type[i][j+1]].length() <= strTmp.length()){
                if (isInside(strTmp,str[type[i][j+1]]) == true){
                    continue;
                }
            }

            int tt = cmp(strTmp,str[type[i][j+1]]);
            tmp += str[type[i][j+1]].length() - tt;
            strTmp += str[type[i][j+1]].substr(tt,str[type[i][j+1]].length());
        }
        ans = min(ans,tmp);
    }
    cout << ans <<'\n';
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值