题意:给你若干个字符串,答案串初始为空。第i 步将第 i 个字符串加到答案串的后面,但是尽量地去掉重复部分(即去掉一个最长的、是原答案串的后缀、也是第 i 个串的前缀的字符串),求最后得到的字符串。
Solution
字符串哈希练习题,做完之后对哈希的理解更深刻了
因为求原字符串的后缀和第i个串的前缀,所以我们可以边记录第i个串的哈希值,边与原字符串进行比较
处理到第i个串的第j位时,如果j比原字符串长度大,可以直接退出
之后边给答案加入第i个串的字符,边处理答案串的哈希值
这里用了一个双hash的方法,从而减少出错率
求区间子串的哈希值
int get_hash(int l,int r,int k)
{
return ((hs_s[r][k]-hs_s[l-1][k]*p[r-l+1][k])%m[k]+m[k])%m[k];
}
AC代码:
int b[2]={171,2333333};
int m[2]={1000000007,999999998};
int p[N][2];
int hs_s[N][2];
int hs_t[N][2];
char s[N];
string t;
void init()
{
p[0][0]=p[0][1]=1;
for(int i=1;i<N-3;i++)
{
p[i][0]=(p[i-1][0]*b[0])%m[0];
p[i][1]=(p[i-1][1]*b[1])%m[1];
}
}
int get_hash(int l,int r,int k)
{
return ((hs_s[r][k]-hs_s[l-1][k]*p[r-l+1][k])%m[k]+m[k])%m[k];
}
void solve()
{
init();
int n;cin>>n;
string x;
cin>>x;
int len=x.length();
hs_s[0][0]=hs_s[0][1]=0;
for(int i=1;i<=len;i++)
{
s[i]=x[i-1];
for(int k=0;k<2;k++)
{
hs_s[i][k]=(hs_s[i-1][k]*b[k]+x[i-1])%m[k];
}
}
for(int i=2;i<=n;i++)
{
cin>>t;
hs_t[0][0]=hs_t[0][1]=0;
int pos=1;
int flag=1;
for(int j=1;j<=t.length()&&len-j+1>0;j++)
{
flag=1;
for(int k=0;k<2;k++)
{
hs_t[j][k]=(t[j-1]+hs_t[j-1][k]*b[k])%m[k];
if(hs_t[j][k]!=get_hash(len-j+1,len,k))flag=0;
/*cout<<hs_t[j][k]<<"\n";
cout<<len-j+1<<" "<<len<<":"<<get_hash(len-j+1,len,k)<<"\n";*/
}
if(flag)pos=j+1;
}
for(int j=pos;j<=t.length();j++)
{
s[++len]=t[j-1];
for(int k=0;k<2;k++)
{
hs_s[len][k]=(hs_s[len-1][k]*b[k]+s[len])%m[k];
}
}
/*cout<<pos<<"\n";
for(int i=1;i<=len;i++)cout<<s[i];
cout<<"\n";*/
}
for(int i=1;i<=len;i++)cout<<s[i];
cout<<"\n";
}
标签:CF1200E,哈希,int,hs,Words,字符串,string,答案
From: https://www.cnblogs.com/HikariFears/p/17288235.html