Description
Input
Output
Sample Input
B
newionyzz
wyxioiwen
1
1 1
Sample Output
16
Data Constraint
Hint
分析:
由于
串取某个后缀,
串取某个前缀,所以可以先把
串反过来。然后就是同时取一段前缀,组合成一个回文串变为一段相同的公共后缀+一个在公共前缀的前面的回文串。这样我们可以把回文树建出来,记录下每个以位置
的结尾的串有多少个,这个显然可以从
转移,对于另一个串也这么做。然后给这个跑一个前缀和,就是找最长公共后缀。这个可以使用二分+字符串hash搞定。但是这题非常恶心的卡空间,好像是为了给manacher过(mdzz), 最后连回文树上的儿子都开了map,打了单hash,总算是卡过了。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <map>
#define LL long long
const int maxn=800007;
const int mod=233333333;
using namespace std;
char a[maxn],b[maxn];
int len1,len2,cnt,test,x,y;
struct node{
int fail,len,sum;
map <int,int> son;
}t[maxn];
LL hash1[maxn],hash2[maxn],bit[maxn];
LL f[maxn],g[maxn];
void pre()
{
for (int i=1;i<=len1;i++)
{
hash1[i]=(hash1[i-1]*26+(a[i]-'a'))%mod;
}
for (int i=1;i<=len2;i++)
{
for (int j=0;j<=1;j++)
{
hash2[i]=(hash2[i-1]*26+(b[i]-'a'))%mod;
}
}
}
void build_tree(char *s,int len,LL *f)
{
for (int i=0;i<maxn;i++)
{
t[i].fail=0;
t[i].len=0;
t[i].sum=0;
t[i].son.clear();
}
cnt=1;
t[0].fail=1;
t[0].len=0;
t[1].fail=0;
t[1].len=-1;
int now=1;
for (int i=1;i<=len;i++)
{
while (s[i]!=s[i-t[now].len-1]) now=t[now].fail;
if (!t[now].son[s[i]-'a'])
{
cnt++;
int k=t[now].fail;
while (s[i]!=s[i-t[k].len-1]) k=t[k].fail;
t[cnt].fail=t[k].son[s[i]-'a'];
t[now].son[s[i]-'a']=cnt;
t[cnt].len=t[now].len+2;
t[cnt].sum=t[t[cnt].fail].sum+1;
}
now=t[now].son[s[i]-'a'];
f[i]=t[now].sum;
}
for (int i=1;i<=len;i++) f[i]=f[i-1]+f[i];
}
bool check(int l,int r,int x,int y)
{
int len1=(r-l)+1,len2=(y-x)+1;
LL h1,h2;
h1=(hash1[r]+mod-hash1[l-1]*bit[len1]%mod)%mod;
h2=(hash2[y]+mod-hash2[x-1]*bit[len2]%mod)%mod;
return (h1==h2);
}
int main()
{
freopen("palindrome.in","r",stdin);
freopen("palindrome.out","w",stdout);
scanf("%s",a);
scanf("%s",a);
scanf("%s",b);
len1=strlen(a);
len2=strlen(b);
for (int i=0;i<=(len1/2)-1;i++) swap(a[i],a[len1-i-1]);
for (int i=len1-1;i>=0;i--) a[i+1]=a[i];
for (int i=len2-1;i>=0;i--) b[i+1]=b[i];
a[0]='#'; b[0]='#';
bit[0]=1;
for (int i=1;i<=max(len1,len2);i++)
{
bit[i]=(bit[i-1]*26)%mod;
}
pre();
build_tree(a,len1,f);
build_tree(b,len2,g);
scanf("%d",&test);
for (int i=1;i<=test;i++)
{
scanf("%d%d",&x,&y);
x=len1-x+1;
y=len2-y+1;
int l=0,r=min(x,y),maxlen=0;
while (l<=r)
{
int mid=(l+r)/2;
if (check(x-mid+1,x,y-mid+1,y)) maxlen=mid,l=mid+1;
else r=mid-1;
}
printf("%lld\n",f[x-1]-f[x-maxlen-1]+g[y-1]-g[y-maxlen-1]+maxlen);
}
}