题解 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;
}
posted @ 2020-09-19 09:50  Hastieyua  阅读(182)  评论(0编辑  收藏  举报