Codeforces 1200E(hash)

传送门c++

题意:

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

分析:

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

咱们只须要动态的去维护答案串的\(\text{hash}\)值,在更新匹配串的\(\text{hash}\)值的同时,将答案串的后缀不断的跟匹配串的前缀匹配,并记录匹配成功的位置\(pos\),最后咱们只须要根据获得的\(pos\)更新答案串的\(\text{hash}\)便可。由于是\(\text{hash}\)值都是动态的进行更新,所以总体的时间复杂度为:\(\mathcal{O}(\sum S)\)code

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

#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;
}
相关文章
相关标签/搜索