Codeforces 1200E(hash)

传送门

题意:

给你n个串,要让你把这个\(n\)个串拼接起来,其中,\(str_i\)的后缀以及\(str_{i+1}\)的前缀中最长的部分只能取一份。

分析:

本题中,我们最主要需要解决的问题是如何快速的判断一个串的后缀是否和另一个串的前缀相同。而我们知道,\(\text{hash}\)可以在\(\mathcal{O}(1)\)的时间对两个串进行比较。因此本题可以用\(\text{hash}\)进行解决。

我们只需要动态的去维护答案串的\(\text{hash}\)值,在更新匹配串的\(\text{hash}\)值的同时,将答案串的后缀不断的跟匹配串的前缀匹配,并记录匹配成功的位置\(pos\),最后我们只需要根据得到的\(pos\)更新答案串的\(\text{hash}\)即可。因为是\(\text{hash}\)值都是动态的进行更新,因此整体的时间复杂度为:\(\mathcal{O}(\sum S)\)

注意:因为整个串的长度已经到达了\(10^6\)的级别,因此为了安全,建议使用双\(\text{hash}\)

#include <bits/stdc++.h>
#define maxn 1000005
using namespace std;
const int mod1=1000000007;
const int mod2=19260817;
typedef long long ll;
typedef pair<ll,ll>pll;
pll hash1[maxn],hash2[maxn];
string str,ans;
ll p1[maxn],p2[maxn];
int main()
{
    p1[0]=p2[0]=1;
    for(int i=1;i<maxn;i++) p1[i]=p1[i-1]*131%mod1;
    for(int i=1;i<maxn;i++) p2[i]=p2[i-1]*133%mod2;

    int n;
    cin>>n;
    cin>>ans;
    for(int i=1;i<=ans.length();i++){
        hash1[i].first=(hash1[i-1].first*131+ans[i-1])%mod1;
        hash1[i].second=(hash1[i-1].second*133+ans[i-1])%mod2;
    }
    for(int i=2;i<=n;i++){
        cin>>str;
        int len1=ans.length(),len2=str.length();
        int pos=0;
        for(int j=1;j<=min(len1,len2);j++){
            hash2[j].first=(hash2[j-1].first*131+str[j-1])%mod1;
            hash2[j].second=(hash2[j-1].second*133+str[j-1])%mod2;
            pll t1;
            t1.first=((hash1[len1].first-hash1[len1-j].first*p1[j])%mod1+mod1)%mod1;
            t1.second=((hash1[len1].second-hash1[len1-j].second*p2[j])%mod2+mod2)%mod2;
            if(t1==hash2[j]) pos=j;
        }
        if(pos<len2) ans+=str.substr(pos);;
        for(int j=len1+1;j<=ans.length();j++){
            hash1[j].first=(hash1[j-1].first*131+ans[j-1])%mod1;
            hash1[j].second=(hash1[j-1].second*133+ans[j-1])%mod2;
        }
    }
    cout<<ans<<endl;
    return 0;
}
posted @ 2019-08-13 16:04  ChenJr  阅读(318)  评论(0编辑  收藏  举报