https://blog.csdn.net/KXL5180/article/details/90142634
http://fastvj.rainng.com/problem/Gym-101981M
http://codeforces.com/gym/101981/attachments
继上一篇文章关于南京M题的做法,这次我有学习了字符串hash有写了一个字符串hash的做法
做法:第一步还是和上次一样用马拉车算法预处理回文串,得到s的以左端点为起点的字符串的个数。
然后对s串哈希,然后在对,t串反转在哈希,最后枚举s串中和t串末尾相同的字符的位置,然后二分LCP长度,然后
ans+=length*sum[i];就可以了
思路和上一次的差不多,唯一不同的就是LCP的求法改变了
时间复杂度是O(nlogn),但不过常数比后缀数组小多了,如果hash的姿势够帅是不会超时的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+10;
const ll p=13131;
const ll mod=1e9+7;
char s[N],t[N],s_new[N];
int d[N],pos[N];
int init()
{
int len=strlen(s);
s_new[0]='$';
s_new[1]='#';
int j=2;
for(int i=0;i<len;i++)
{
s_new[j++]=s[i];
s_new[j++]='#';
}
s_new[j]='\0';
return j;
}
void Manacher()
{
int len=init();
int id,mx=0;
for(int i=1;i<len;i++)
{
if(i<mx) pos[i]=min(pos[2*id-i],mx-i);
else pos[i]=1;
while(s_new[i-pos[i]]==s_new[i+pos[i]])
pos[i]++;
if(mx<i+pos[i]){
id=i;mx=i+pos[i];
}
}
for(int i=2;i<len;i++)
{
if(s_new[i]=='#'&&pos[i]==1) continue;
int x=i/2-pos[i]/2+1;
int y=x+i/2+pos[i]/2-!(i&1);
d[x]++;
d[y/2+1]--;
}
}
ll hs1[N],hs2[N],pw[N];
ll geths(ll *hs,int l,int r)
{
return (hs[r]-hs[l-1]*pw[r-l+1]%mod+mod)%mod;
}
int ok(int len,int p,int t_len)
{
ll t1=geths(hs1,p-len+1,p);
ll t2=geths(hs2,t_len-len+1,t_len);
if(t1==t2) return 1;
return 0;
}
int main()
{
pw[0]=1;
for(int i=1;i<1000003;i++){
pw[i]=pw[i-1]*p%mod;
}
scanf("%s%s",s,t);
Manacher();
int len=strlen(s);
for(int i=1;i<=len;i++) {
d[i]+=d[i-1];
}
hs1[0]=hs2[0]=1;
for(int i=0;i<len;i++){
hs1[i+1]=(hs1[i]*p+s[i])%mod;
}
int t_len=strlen(t);
reverse(t,t+t_len);
for(int i=0;i<t_len;i++){
hs2[i+1]=(hs2[i]*p+t[i])%mod;
}
ll ans=0;
for(int i=0;i<len-1;i++){
if(s[i]!=t[t_len-1]) continue;
int l=1,r=min(i+1,t_len),mid,cnt=0;
while(l<=r){
mid=(l+r)>>1;
if(ok(mid,i+1,t_len))
cnt=mid,l=mid+1;
else
r=mid-1;
}
ans+=1LL*cnt*d[i+2];
}
printf("%lld\n",ans);
return 0;
}