题解 CF17E 【Palisection】
卡空间PAM,2010没有PAM,所以都是马拉车
众所周知,PAM拥有十分优秀的时间复杂度,但空间复杂度lj得不行
但这题卡空间,所以得用到邻接链表PAM
先讲思路
题目要求相交的回文子串对,这很难做
于是我们求补集,求不相交的回文子串对,再用总数减即可
求法和上文的最长双回文子串 类似
正反建一次PAM,存该位置结尾的回文子串个数,然后加法改乘法
自己领悟一下,挺简单的。
现在讲一下邻接链表PAM
注意:邻接链表PAM不是使空间变小了,而是用时间换空间
我们记边结构体\(line\)
存\(3\)个信息:\(nx,to,w\) 分别表示上一条边,这条边通向的节点编号,这条边是代表哪个字符
数组\(fir[i]\)表示\(i\)伸出的最后一条边的编号(头插式
当我们要寻找\(u\)的\(v\)儿子
我们就像邻接链表一样找,直到有一条边的\(w==v\)为止
找不到记得指根
int getson(int u,int v){
for(int i=u;i!=-1;i=l[i].nx)
if(l[i].w==v)return l[i].to;
return -1;
}
建点的时候把边建上
void insert(int u,int i){
int Fail=getfail(pre,i),ls=getfail(fail[Fail],i);
if(getson(fir[Fail],u)==-1){
if(getson(fir[ls],u)==-1)fail[++tot]=0; //找不到指根
else fail[++tot]=getson(fir[ls],u); //找到了
l[++cnt]=(line){fir[Fail],tot,u};fir[Fail]=cnt; //加边
len[tot]=len[Fail]+2;
ans[tot]=ans[fail[tot]]+1; //结尾回文子串个数
pre=tot;
}else
pre=getson(fir[Fail],u);
}
然鹅事实上你仍然过不了,你还要继续压空间,省掉一堆数组就可以过啦!
总代码:
#include<bits/stdc++.h>
#define maxn 2000005
#define mod 51123987
using namespace std;
char s[maxn];
int slen,b[maxn];
long long res;
int fail[maxn],len[maxn],ans[maxn],fir[maxn];
struct line{int nx,to,w;}l[maxn];
int tot,pre,cnt;
void init(){
memset(fir,-1,sizeof(fir));cnt=0;
fail[0]=1;len[1]=-1;tot=1;pre=0;
}
int getfail(int x,int i){
while(i-len[x]-1<0||s[i-len[x]-1]!=s[i])x=fail[x];
return x;
}
int getson(int u,int v){
for(int i=u;i!=-1;i=l[i].nx)
if(l[i].w==v)return l[i].to;
return -1;
}
void insert(int u,int i){
int Fail=getfail(pre,i),ls=getfail(fail[Fail],i);
if(getson(fir[Fail],u)==-1){
if(getson(fir[ls],u)==-1)fail[++tot]=0;
else fail[++tot]=getson(fir[ls],u);
l[++cnt]=(line){fir[Fail],tot,u};fir[Fail]=cnt;
len[tot]=len[Fail]+2;
ans[tot]=ans[fail[tot]]+1;
pre=tot;
}else
pre=getson(fir[Fail],u);
}
int main(){
int n;
scanf("%d",&n);
scanf("%s",s);slen=strlen(s);init();
reverse(s,s+slen);
for(int i=0;i<slen;i++)insert(s[i]-'a',i),b[slen-i-1]=ans[pre];
for(int i=slen-1;i>=0;i--)b[i]+=b[i+1],b[i]%=mod;
reverse(s,s+slen);init();
for(int i=0;i<slen-1;i++){
insert(s[i]-'a',i);int x=ans[pre];
res+=(1ll*x*b[i+1])%mod,res%=mod;
}
printf("%lld\n",((1ll*b[0]*(b[0]-1)/2ll)%mod-res+mod)%mod);
return 0;
}
点赞嗷 ~ \ QwQ / *