[codeforces] 25E Test || hash

本文介绍了一种寻找包含三个特定字符串的最短字符串的方法。通过预先计算哈希值来加速字符串匹配过程,并采用递归方法尝试所有可能的组合。此外,文章还提供了一个完整的C++实现示例。

原题

给你三个字符串,找一个字符串(它的子串含有以上三个字符串),输出此字符串的长度。


先暴力判断是否有包含,消减需要匹配的串的数量。因为只有三个字符串,所以暴力枚举三个串的位置关系,对三个串跑好哈希,然后判断后缀与前缀重合长度即可。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define mo 99994711
typedef long long ll;
using namespace std;
int is1=1,is2=1,all=3,base=1314,ord[4],ans,l[4];
long long num[4][100010],bs[100010];
bool vis[4];
char s[4][100010];

ll gethash(int x,int st,int l)
{
    ll ans=0;
    ans=bs[100005-st]*(num[x][st+l-1]-(st==0? 0 : num[x][st-1]))%mo;
    return (ans%mo+mo)%mo;
}

bool in(int x,int y)
{
    ll u,v;
    for (int i=0;i<l[y]-l[x];i++)
    {
    u=gethash(y,i,l[x]);
    v=num[x][l[x]-1]*bs[100005]%mo;
    if (u==v) return 1;
    }
    return 0;
}

int mini(int x,int y)
{
    ll u,v;
    int ans=0;
    for (int i=1;i<=min(l[x],l[y]);i++)
    {
    u=gethash(x,l[x]-i,i);
    v=gethash(y,0,i);
    if (u==v) ans=i; 
    }
    return ans;
}

void hsh(int x)
{
    for (int i=0;i<l[x];i++)
    if (i) num[x][i]=(num[x][i-1]+(ll)(s[x][i]-'a'+1)*bs[i])%mo;
    else num[x][i]=s[x][i]-'a'+1;
}

void dfs(int x)
{
    if (x>3)
    {
    ans=min(ans,l[1]+l[2]+l[3]-mini(ord[1],ord[2])-mini(ord[2],ord[3]));
    return ;
    }
    for (int i=1;i<=3;i++)
    if (!vis[i])
    {
        vis[i]=1;
        ord[x]=i;
        dfs(x+1);
        vis[i]=0;
    }
}

void st()
{
    if (l[1]>l[2]) swap(l[1],l[2]),swap(s[1],s[2]);
    if (l[2]>l[3]) swap(l[2],l[3]),swap(s[2],s[3]);
    if (l[1]>l[2]) swap(l[1],l[2]),swap(s[1],s[2]);
}

int main()
{
    ans=0x7fffffff;
    bs[0]=1;
    for (int i=1;i<=100005;i++) bs[i]=bs[i-1]*base%mo;
    scanf("%s%s%s",s[1],s[2],s[3]);
    l[1]=strlen(s[1]);
    l[2]=strlen(s[2]);
    l[3]=strlen(s[3]);
    st();
    hsh(1);
    hsh(2);
    hsh(3);
    if (in(1,2)) is1=0,all--;
    if (in(2,3)) is2=0,all--;
    if (is1 && in(1,3)) is1=0,all--;
    if (all==1)
    {
    printf("%d\n",l[3]);
    return 0;
    }
    if (all==2)
    {
    if (!is2 && is1) swap(s[1],s[2]),swap(l[1],l[2]);
    hsh(2);
    hsh(3);
    printf("%d\n",l[2]+l[3]-max(mini(2,3),mini(3,2)));
    }
    else
    {
    dfs(1);
    printf("%d\n",ans);
    }
    return 0;
}

转载于:https://www.cnblogs.com/mrha/p/8024224.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值